xref: /reactos/dll/win32/cryptdlg/main.c (revision 8a978a17)
1 /*
2  * Copyright 2008 Maarten Lankhorst
3  *
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.
8  *
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.
13  *
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
17  */
18 
19 #define NONAMELESSUNION
20 
21 #include <stdarg.h>
22 #ifdef __REACTOS__
23 #include <wchar.h>
24 #endif
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "wincrypt.h"
31 #include "wintrust.h"
32 #include "winuser.h"
33 #include "objbase.h"
34 #include "cryptdlg.h"
35 #include "cryptuiapi.h"
36 #include "cryptres.h"
37 #include "wine/debug.h"
38 
39 WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg);
40 
41 static HINSTANCE hInstance;
42 
43 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
44 {
45     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
46 
47     switch (fdwReason)
48     {
49         case DLL_WINE_PREATTACH:
50             return FALSE;    /* prefer native version */
51         case DLL_PROCESS_ATTACH:
52             DisableThreadLibraryCalls(hinstDLL);
53             hInstance = hinstDLL;
54             break;
55     }
56     return TRUE;
57 }
58 
59 /***********************************************************************
60  *		GetFriendlyNameOfCertA (CRYPTDLG.@)
61  */
62 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
63                              DWORD cchBuffer)
64 {
65     return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
66      pchBuffer, cchBuffer);
67 }
68 
69 /***********************************************************************
70  *		GetFriendlyNameOfCertW (CRYPTDLG.@)
71  */
72 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
73                              DWORD cchBuffer)
74 {
75     return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
76      pchBuffer, cchBuffer);
77 }
78 
79 /***********************************************************************
80  *		CertTrustInit (CRYPTDLG.@)
81  */
82 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
83 {
84     HRESULT ret = S_FALSE;
85 
86     TRACE("(%p)\n", pProvData);
87 
88     if (pProvData->padwTrustStepErrors &&
89      !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
90         ret = S_OK;
91     TRACE("returning %08x\n", ret);
92     return ret;
93 }
94 
95 /***********************************************************************
96  *		CertTrustCertPolicy (CRYPTDLG.@)
97  */
98 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
99 {
100     FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
101     return FALSE;
102 }
103 
104 /***********************************************************************
105  *		CertTrustCleanup (CRYPTDLG.@)
106  */
107 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
108 {
109     FIXME("(%p)\n", pProvData);
110     return E_NOTIMPL;
111 }
112 
113 static BOOL CRYPTDLG_CheckOnlineCRL(void)
114 {
115     static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e',
116      '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g',
117      'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f',
118      '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9',
119      '7','9','3','8','7','e','a','}',0 };
120     static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a',
121      'g','s',0 };
122     HKEY key;
123     BOOL ret = FALSE;
124 
125     if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
126     {
127         DWORD type, flags, size = sizeof(flags);
128 
129         if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
130          &size) && type == REG_DWORD)
131         {
132             /* The flag values aren't defined in any header I'm aware of, but
133              * this value is well documented on the net.
134              */
135             if (flags & 0x00010000)
136                 ret = TRUE;
137         }
138         RegCloseKey(key);
139     }
140     return ret;
141 }
142 
143 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
144  * is.
145  */
146 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
147 {
148     BOOL ret;
149     BYTE hash[20];
150     DWORD size = sizeof(hash);
151 
152     if ((ret = CertGetCertificateContextProperty(pCert,
153      CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
154     {
155         static const WCHAR disallowedW[] =
156          { 'D','i','s','a','l','l','o','w','e','d',0 };
157         HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
158          X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW);
159 
160         if (disallowed)
161         {
162             PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
163              X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
164 
165             if (found)
166             {
167                 ret = FALSE;
168                 CertFreeCertificateContext(found);
169             }
170             CertCloseStore(disallowed, 0);
171         }
172     }
173     return ret;
174 }
175 
176 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
177 {
178     DWORD confidence = 0;
179 
180     confidence = 0;
181     if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
182         confidence |= CERT_CONFIDENCE_SIG;
183     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
184         confidence |= CERT_CONFIDENCE_TIME;
185     if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
186         confidence |= CERT_CONFIDENCE_TIMENEST;
187     return confidence;
188 }
189 
190 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
191  PCCERT_CHAIN_CONTEXT chain)
192 {
193     BOOL ret;
194     CRYPT_PROVIDER_SGNR signer;
195     PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
196     DWORD i;
197 
198     memset(&signer, 0, sizeof(signer));
199     signer.cbStruct = sizeof(signer);
200     ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
201     if (ret)
202     {
203         CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
204          FALSE, 0);
205 
206         if (sgnr)
207         {
208             sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
209             sgnr->pChainContext = CertDuplicateCertificateChain(chain);
210         }
211         else
212             ret = FALSE;
213         for (i = 0; ret && i < simpleChain->cElement; i++)
214         {
215             ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
216              simpleChain->rgpElement[i]->pCertContext);
217             if (ret)
218             {
219                 CRYPT_PROVIDER_CERT *cert;
220 
221                 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
222                 {
223                     CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
224 
225                     cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
226                      element->TrustStatus.dwErrorStatus);
227                     cert->dwError = element->TrustStatus.dwErrorStatus;
228                     cert->pChainElement = element;
229                 }
230                 else
231                     ret = FALSE;
232             }
233         }
234     }
235     return ret;
236 }
237 
238 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
239  CRYPT_PROVIDER_DATA *data)
240 {
241     CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
242 
243     /* This should always be true, but just in case the calling function is
244      * called directly:
245      */
246     if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
247      data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject ==
248      sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
249      data->pWintrustData->u.pBlob->pbMemObject)
250          pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
251           data->pWintrustData->u.pBlob->pbMemObject;
252     return pCert;
253 }
254 
255 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
256 {
257     HCERTCHAINENGINE engine = NULL;
258     HCERTSTORE root = NULL, trust = NULL;
259     DWORD i;
260 
261     if (cert->cRootStores)
262     {
263         root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
264          CERT_STORE_CREATE_NEW_FLAG, NULL);
265         if (root)
266         {
267             for (i = 0; i < cert->cRootStores; i++)
268                 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
269         }
270     }
271     if (cert->cTrustStores)
272     {
273         trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
274          CERT_STORE_CREATE_NEW_FLAG, NULL);
275         if (trust)
276         {
277             for (i = 0; i < cert->cTrustStores; i++)
278                 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
279         }
280     }
281     if (cert->cRootStores || cert->cStores || cert->cTrustStores)
282     {
283         CERT_CHAIN_ENGINE_CONFIG config;
284 
285         memset(&config, 0, sizeof(config));
286         config.cbSize = sizeof(config);
287         config.hRestrictedRoot = root;
288         config.hRestrictedTrust = trust;
289         config.cAdditionalStore = cert->cStores;
290         config.rghAdditionalStore = cert->rghstoreCAs;
291         config.hRestrictedRoot = root;
292         CertCreateCertificateChainEngine(&config, &engine);
293         CertCloseStore(root, 0);
294         CertCloseStore(trust, 0);
295     }
296     return engine;
297 }
298 
299 /***********************************************************************
300  *		CertTrustFinalPolicy (CRYPTDLG.@)
301  */
302 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
303 {
304     BOOL ret;
305     DWORD err = S_OK;
306     CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
307 
308     TRACE("(%p)\n", data);
309 
310     if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
311         FIXME("unimplemented for UI choice %d\n",
312          data->pWintrustData->dwUIChoice);
313     if (pCert)
314     {
315         DWORD flags = 0;
316         CERT_CHAIN_PARA chainPara;
317         HCERTCHAINENGINE engine;
318 
319         memset(&chainPara, 0, sizeof(chainPara));
320         chainPara.cbSize = sizeof(chainPara);
321         if (CRYPTDLG_CheckOnlineCRL())
322             flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
323         engine = CRYPTDLG_MakeEngine(pCert);
324         GetSystemTimeAsFileTime(&data->sftSystemTime);
325         ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
326         if (ret)
327         {
328             PCCERT_CHAIN_CONTEXT chain;
329 
330             ret = CertGetCertificateChain(engine, pCert->pccert,
331              &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
332             if (ret)
333             {
334                 if (chain->cChain != 1)
335                 {
336                     FIXME("unimplemented for more than 1 simple chain\n");
337                     err = TRUST_E_SUBJECT_FORM_UNKNOWN;
338                     ret = FALSE;
339                 }
340                 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
341                 {
342                     if (CertVerifyTimeValidity(&data->sftSystemTime,
343                      pCert->pccert->pCertInfo))
344                     {
345                         ret = FALSE;
346                         err = CERT_E_EXPIRED;
347                     }
348                 }
349                 else
350                     err = TRUST_E_SYSTEM_ERROR;
351                 CertFreeCertificateChain(chain);
352             }
353             else
354                 err = TRUST_E_SUBJECT_NOT_TRUSTED;
355         }
356         CertFreeCertificateChainEngine(engine);
357     }
358     else
359     {
360         ret = FALSE;
361         err = TRUST_E_NOSIGNATURE;
362     }
363     /* Oddly, native doesn't set the error in the trust step error location,
364      * probably because this action is more advisory than anything else.
365      * Instead it stores it as the final error, but the function "succeeds" in
366      * any case.
367      */
368     if (!ret)
369         data->dwFinalError = err;
370     TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
371     return S_OK;
372 }
373 
374 /***********************************************************************
375  *		CertViewPropertiesA (CRYPTDLG.@)
376  */
377 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
378 {
379     CERT_VIEWPROPERTIES_STRUCT_W infoW;
380     LPWSTR title = NULL;
381     BOOL ret;
382 
383     TRACE("(%p)\n", info);
384 
385     memcpy(&infoW, info, sizeof(infoW));
386     if (info->szTitle)
387     {
388         int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
389 
390         title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
391         if (title)
392         {
393             MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
394             infoW.szTitle = title;
395         }
396         else
397         {
398             ret = FALSE;
399             goto error;
400         }
401     }
402     ret = CertViewPropertiesW(&infoW);
403     HeapFree(GetProcessHeap(), 0, title);
404 error:
405     return ret;
406 }
407 
408 /***********************************************************************
409  *		CertViewPropertiesW (CRYPTDLG.@)
410  */
411 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
412 {
413     static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
414     CERT_VERIFY_CERTIFICATE_TRUST trust;
415     WINTRUST_BLOB_INFO blob;
416     WINTRUST_DATA wtd;
417     LONG err;
418     BOOL ret;
419 
420     TRACE("(%p)\n", info);
421 
422     memset(&trust, 0, sizeof(trust));
423     trust.cbSize = sizeof(trust);
424     trust.pccert = info->pCertContext;
425     trust.cRootStores = info->cRootStores;
426     trust.rghstoreRoots = info->rghstoreRoots;
427     trust.cStores = info->cStores;
428     trust.rghstoreCAs = info->rghstoreCAs;
429     trust.cTrustStores = info->cTrustStores;
430     trust.rghstoreTrust = info->rghstoreTrust;
431     memset(&blob, 0, sizeof(blob));
432     blob.cbStruct = sizeof(blob);
433     blob.cbMemObject = sizeof(trust);
434     blob.pbMemObject = (BYTE *)&trust;
435     memset(&wtd, 0, sizeof(wtd));
436     wtd.cbStruct = sizeof(wtd);
437     wtd.dwUIChoice = WTD_UI_NONE;
438     wtd.dwUnionChoice = WTD_CHOICE_BLOB;
439     wtd.u.pBlob = &blob;
440     wtd.dwStateAction = WTD_STATEACTION_VERIFY;
441     err = WinVerifyTrust(NULL, &cert_action_verify, &wtd);
442     if (err == ERROR_SUCCESS)
443     {
444         CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
445         BOOL propsChanged = FALSE;
446 
447         memset(&uiInfo, 0, sizeof(uiInfo));
448         uiInfo.dwSize = sizeof(uiInfo);
449         uiInfo.hwndParent = info->hwndParent;
450         uiInfo.dwFlags =
451          CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES;
452         uiInfo.szTitle = info->szTitle;
453         uiInfo.pCertContext = info->pCertContext;
454         uiInfo.cPurposes = info->cArrayPurposes;
455         uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes;
456         uiInfo.u.hWVTStateData = wtd.hWVTStateData;
457         uiInfo.fpCryptProviderDataTrustedUsage = TRUE;
458         uiInfo.cPropSheetPages = info->cArrayPropSheetPages;
459         uiInfo.rgPropSheetPages = info->arrayPropSheetPages;
460         uiInfo.nStartPage = info->nStartPage;
461         ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged);
462         wtd.dwStateAction = WTD_STATEACTION_CLOSE;
463         WinVerifyTrust(NULL, &cert_action_verify, &wtd);
464     }
465     else
466         ret = FALSE;
467     return ret;
468 }
469 
470 static BOOL CRYPT_FormatHexString(const BYTE *pbEncoded, DWORD cbEncoded,
471  WCHAR *str, DWORD *pcchStr)
472 {
473     BOOL ret;
474     DWORD charsNeeded;
475 
476     if (cbEncoded)
477         charsNeeded = (cbEncoded * 3);
478     else
479         charsNeeded = 1;
480     if (!str)
481     {
482         *pcchStr = charsNeeded;
483         ret = TRUE;
484     }
485     else if (*pcchStr < charsNeeded)
486     {
487         *pcchStr = charsNeeded;
488         SetLastError(ERROR_MORE_DATA);
489         ret = FALSE;
490     }
491     else
492     {
493         static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
494         static const WCHAR endFmt[] = { '%','0','2','x',0 };
495         DWORD i;
496         LPWSTR ptr = str;
497 
498         *pcchStr = charsNeeded;
499         if (cbEncoded)
500         {
501             for (i = 0; i < cbEncoded; i++)
502             {
503                 if (i < cbEncoded - 1)
504                     ptr += swprintf(ptr, fmt, pbEncoded[i]);
505                 else
506                     ptr += swprintf(ptr, endFmt, pbEncoded[i]);
507             }
508         }
509         else
510             *ptr = 0;
511         ret = TRUE;
512     }
513     return ret;
514 }
515 
516 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
517 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
518 static const WCHAR colonSpace[] = { ':',' ',0 };
519 static const WCHAR crlf[] = { '\r','\n',0 };
520 static const WCHAR commaSep[] = { ',',' ',0 };
521 
522 static BOOL CRYPT_FormatCPS(DWORD dwCertEncodingType,
523  DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
524  WCHAR *str, DWORD *pcchStr)
525 {
526     BOOL ret;
527     DWORD size, charsNeeded = 1;
528     CERT_NAME_VALUE *cpsValue;
529 
530     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
531      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &cpsValue, &size)))
532     {
533         LPCWSTR sep;
534         DWORD sepLen;
535 
536         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
537             sep = crlf;
538         else
539             sep = commaSep;
540 
541         sepLen = lstrlenW(sep);
542 
543         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
544         {
545             charsNeeded += 3 * lstrlenW(indent);
546             if (str && *pcchStr >= charsNeeded)
547             {
548                 lstrcpyW(str, indent);
549                 str += lstrlenW(indent);
550                 lstrcpyW(str, indent);
551                 str += lstrlenW(indent);
552                 lstrcpyW(str, indent);
553                 str += lstrlenW(indent);
554             }
555         }
556         charsNeeded += cpsValue->Value.cbData / sizeof(WCHAR);
557         if (str && *pcchStr >= charsNeeded)
558         {
559             lstrcpyW(str, (LPWSTR)cpsValue->Value.pbData);
560             str += cpsValue->Value.cbData / sizeof(WCHAR);
561         }
562         charsNeeded += sepLen;
563         if (str && *pcchStr >= charsNeeded)
564         {
565             lstrcpyW(str, sep);
566             str += sepLen;
567         }
568         LocalFree(cpsValue);
569         if (!str)
570             *pcchStr = charsNeeded;
571         else if (*pcchStr < charsNeeded)
572         {
573             *pcchStr = charsNeeded;
574             SetLastError(ERROR_MORE_DATA);
575             ret = FALSE;
576         }
577         else
578             *pcchStr = charsNeeded;
579     }
580     return ret;
581 }
582 
583 static BOOL CRYPT_FormatUserNotice(DWORD dwCertEncodingType,
584  DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
585  WCHAR *str, DWORD *pcchStr)
586 {
587     BOOL ret;
588     DWORD size, charsNeeded = 1;
589     CERT_POLICY_QUALIFIER_USER_NOTICE *notice;
590 
591     if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
592      X509_PKIX_POLICY_QUALIFIER_USERNOTICE, pbEncoded, cbEncoded,
593      CRYPT_DECODE_ALLOC_FLAG, NULL, &notice, &size)))
594     {
595         static const WCHAR numFmt[] = { '%','d',0 };
596         CERT_POLICY_QUALIFIER_NOTICE_REFERENCE *pNoticeRef =
597          notice->pNoticeReference;
598         LPCWSTR headingSep, sep;
599         DWORD headingSepLen, sepLen;
600         LPWSTR noticeRef, organization, noticeNum, noticeText;
601         DWORD noticeRefLen, organizationLen, noticeNumLen, noticeTextLen;
602         WCHAR noticeNumStr[11];
603 
604         noticeRefLen = LoadStringW(hInstance, IDS_NOTICE_REF,
605          (LPWSTR)&noticeRef, 0);
606         organizationLen = LoadStringW(hInstance, IDS_ORGANIZATION,
607          (LPWSTR)&organization, 0);
608         noticeNumLen = LoadStringW(hInstance, IDS_NOTICE_NUM,
609          (LPWSTR)&noticeNum, 0);
610         noticeTextLen = LoadStringW(hInstance, IDS_NOTICE_TEXT,
611          (LPWSTR)&noticeText, 0);
612         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
613         {
614             headingSep = colonCrlf;
615             sep = crlf;
616         }
617         else
618         {
619             headingSep = colonSpace;
620             sep = commaSep;
621         }
622         sepLen = lstrlenW(sep);
623         headingSepLen = lstrlenW(headingSep);
624 
625         if (pNoticeRef)
626         {
627             DWORD k;
628             LPCSTR src;
629 
630             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
631             {
632                 charsNeeded += 3 * lstrlenW(indent);
633                 if (str && *pcchStr >= charsNeeded)
634                 {
635                     lstrcpyW(str, indent);
636                     str += lstrlenW(indent);
637                     lstrcpyW(str, indent);
638                     str += lstrlenW(indent);
639                     lstrcpyW(str, indent);
640                     str += lstrlenW(indent);
641                 }
642             }
643             charsNeeded += noticeRefLen;
644             if (str && *pcchStr >= charsNeeded)
645             {
646                 memcpy(str, noticeRef, noticeRefLen * sizeof(WCHAR));
647                 str += noticeRefLen;
648             }
649             charsNeeded += headingSepLen;
650             if (str && *pcchStr >= charsNeeded)
651             {
652                 lstrcpyW(str, headingSep);
653                 str += headingSepLen;
654             }
655             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
656             {
657                 charsNeeded += 4 * lstrlenW(indent);
658                 if (str && *pcchStr >= charsNeeded)
659                 {
660                     lstrcpyW(str, indent);
661                     str += lstrlenW(indent);
662                     lstrcpyW(str, indent);
663                     str += lstrlenW(indent);
664                     lstrcpyW(str, indent);
665                     str += lstrlenW(indent);
666                     lstrcpyW(str, indent);
667                     str += lstrlenW(indent);
668                 }
669             }
670             charsNeeded += organizationLen;
671             if (str && *pcchStr >= charsNeeded)
672             {
673                 memcpy(str, organization, organizationLen * sizeof(WCHAR));
674                 str += organizationLen;
675             }
676             charsNeeded += strlen(pNoticeRef->pszOrganization);
677             if (str && *pcchStr >= charsNeeded)
678                 for (src = pNoticeRef->pszOrganization; src && *src;
679                  src++, str++)
680                     *str = *src;
681             charsNeeded += sepLen;
682             if (str && *pcchStr >= charsNeeded)
683             {
684                 lstrcpyW(str, sep);
685                 str += sepLen;
686             }
687             for (k = 0; k < pNoticeRef->cNoticeNumbers; k++)
688             {
689                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
690                 {
691                     charsNeeded += 4 * lstrlenW(indent);
692                     if (str && *pcchStr >= charsNeeded)
693                     {
694                         lstrcpyW(str, indent);
695                         str += lstrlenW(indent);
696                         lstrcpyW(str, indent);
697                         str += lstrlenW(indent);
698                         lstrcpyW(str, indent);
699                         str += lstrlenW(indent);
700                         lstrcpyW(str, indent);
701                         str += lstrlenW(indent);
702                     }
703                 }
704                 charsNeeded += noticeNumLen;
705                 if (str && *pcchStr >= charsNeeded)
706                 {
707                     memcpy(str, noticeNum, noticeNumLen * sizeof(WCHAR));
708                     str += noticeNumLen;
709                 }
710                 swprintf(noticeNumStr, numFmt, k + 1);
711                 charsNeeded += lstrlenW(noticeNumStr);
712                 if (str && *pcchStr >= charsNeeded)
713                 {
714                     lstrcpyW(str, noticeNumStr);
715                     str += lstrlenW(noticeNumStr);
716                 }
717                 charsNeeded += sepLen;
718                 if (str && *pcchStr >= charsNeeded)
719                 {
720                     lstrcpyW(str, sep);
721                     str += sepLen;
722                 }
723             }
724         }
725         if (notice->pszDisplayText)
726         {
727             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
728             {
729                 charsNeeded += 3 * lstrlenW(indent);
730                 if (str && *pcchStr >= charsNeeded)
731                 {
732                     lstrcpyW(str, indent);
733                     str += lstrlenW(indent);
734                     lstrcpyW(str, indent);
735                     str += lstrlenW(indent);
736                     lstrcpyW(str, indent);
737                     str += lstrlenW(indent);
738                 }
739             }
740             charsNeeded += noticeTextLen;
741             if (str && *pcchStr >= charsNeeded)
742             {
743                 memcpy(str, noticeText, noticeTextLen * sizeof(WCHAR));
744                 str += noticeTextLen;
745             }
746             charsNeeded += lstrlenW(notice->pszDisplayText);
747             if (str && *pcchStr >= charsNeeded)
748             {
749                 lstrcpyW(str, notice->pszDisplayText);
750                 str += lstrlenW(notice->pszDisplayText);
751             }
752             charsNeeded += sepLen;
753             if (str && *pcchStr >= charsNeeded)
754             {
755                 lstrcpyW(str, sep);
756                 str += sepLen;
757             }
758         }
759         LocalFree(notice);
760         if (!str)
761             *pcchStr = charsNeeded;
762         else if (*pcchStr < charsNeeded)
763         {
764             *pcchStr = charsNeeded;
765             SetLastError(ERROR_MORE_DATA);
766             ret = FALSE;
767         }
768         else
769             *pcchStr = charsNeeded;
770     }
771     return ret;
772 }
773 
774 /***********************************************************************
775  *		FormatVerisignExtension (CRYPTDLG.@)
776  */
777 BOOL WINAPI FormatVerisignExtension(DWORD dwCertEncodingType,
778  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
779  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
780  DWORD *pcbFormat)
781 {
782     CERT_POLICIES_INFO *policies;
783     DWORD size;
784     BOOL ret = FALSE;
785 
786     if (!cbEncoded)
787     {
788         SetLastError(E_INVALIDARG);
789         return FALSE;
790     }
791     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_POLICIES,
792      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size)))
793     {
794         static const WCHAR numFmt[] = { '%','d',0 };
795         DWORD charsNeeded = 1; /* space for NULL terminator */
796         LPCWSTR headingSep, sep;
797         DWORD headingSepLen, sepLen;
798         WCHAR policyNum[11], policyQualifierNum[11];
799         LPWSTR certPolicy, policyId, policyQualifierInfo, policyQualifierId;
800         LPWSTR cps, userNotice, qualifier;
801         DWORD certPolicyLen, policyIdLen, policyQualifierInfoLen;
802         DWORD policyQualifierIdLen, cpsLen, userNoticeLen, qualifierLen;
803         DWORD i;
804         LPWSTR str = pbFormat;
805 
806         certPolicyLen = LoadStringW(hInstance, IDS_CERT_POLICY,
807          (LPWSTR)&certPolicy, 0);
808         policyIdLen = LoadStringW(hInstance, IDS_POLICY_ID, (LPWSTR)&policyId,
809          0);
810         policyQualifierInfoLen = LoadStringW(hInstance,
811          IDS_POLICY_QUALIFIER_INFO, (LPWSTR)&policyQualifierInfo, 0);
812         policyQualifierIdLen = LoadStringW(hInstance, IDS_POLICY_QUALIFIER_ID,
813          (LPWSTR)&policyQualifierId, 0);
814         cpsLen = LoadStringW(hInstance, IDS_CPS, (LPWSTR)&cps, 0);
815         userNoticeLen = LoadStringW(hInstance, IDS_USER_NOTICE,
816          (LPWSTR)&userNotice, 0);
817         qualifierLen = LoadStringW(hInstance, IDS_QUALIFIER,
818          (LPWSTR)&qualifier, 0);
819         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
820         {
821             headingSep = colonCrlf;
822             sep = crlf;
823         }
824         else
825         {
826             headingSep = colonSpace;
827             sep = commaSep;
828         }
829         sepLen = lstrlenW(sep);
830         headingSepLen = lstrlenW(headingSep);
831 
832         for (i = 0; ret && i < policies->cPolicyInfo; i++)
833         {
834             CERT_POLICY_INFO *policy = &policies->rgPolicyInfo[i];
835             DWORD j;
836             LPCSTR src;
837 
838             charsNeeded += 1; /* '['*/
839             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
840                 *str++ = '[';
841             swprintf(policyNum, numFmt, i + 1);
842             charsNeeded += lstrlenW(policyNum);
843             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
844             {
845                 lstrcpyW(str, policyNum);
846                 str += lstrlenW(policyNum);
847             }
848             charsNeeded += 1; /* ']'*/
849             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
850                 *str++ = ']';
851             charsNeeded += certPolicyLen;
852             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
853             {
854                 memcpy(str, certPolicy, certPolicyLen * sizeof(WCHAR));
855                 str += certPolicyLen;
856             }
857             charsNeeded += headingSepLen;
858             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
859             {
860                 lstrcpyW(str, headingSep);
861                 str += headingSepLen;
862             }
863             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
864             {
865                 charsNeeded += lstrlenW(indent);
866                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
867                 {
868                     lstrcpyW(str, indent);
869                     str += lstrlenW(indent);
870                 }
871             }
872             charsNeeded += policyIdLen;
873             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
874             {
875                 memcpy(str, policyId, policyIdLen * sizeof(WCHAR));
876                 str += policyIdLen;
877             }
878             charsNeeded += strlen(policy->pszPolicyIdentifier);
879             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
880             {
881                 for (src = policy->pszPolicyIdentifier; src && *src;
882                  src++, str++)
883                     *str = *src;
884             }
885             charsNeeded += sepLen;
886             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
887             {
888                 lstrcpyW(str, sep);
889                 str += sepLen;
890             }
891             for (j = 0; j < policy->cPolicyQualifier; j++)
892             {
893                 CERT_POLICY_QUALIFIER_INFO *qualifierInfo =
894                  &policy->rgPolicyQualifier[j];
895                 DWORD sizeRemaining;
896 
897                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
898                 {
899                     charsNeeded += lstrlenW(indent);
900                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
901                     {
902                         lstrcpyW(str, indent);
903                         str += lstrlenW(indent);
904                     }
905                 }
906                 charsNeeded += 1; /* '['*/
907                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
908                     *str++ = '[';
909                 charsNeeded += lstrlenW(policyNum);
910                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
911                 {
912                     lstrcpyW(str, policyNum);
913                     str += lstrlenW(policyNum);
914                 }
915                 charsNeeded += 1; /* ','*/
916                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
917                     *str++ = ',';
918                 swprintf(policyQualifierNum, numFmt, j + 1);
919                 charsNeeded += lstrlenW(policyQualifierNum);
920                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
921                 {
922                     lstrcpyW(str, policyQualifierNum);
923                     str += lstrlenW(policyQualifierNum);
924                 }
925                 charsNeeded += 1; /* ']'*/
926                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
927                     *str++ = ']';
928                 charsNeeded += policyQualifierInfoLen;
929                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
930                 {
931                     memcpy(str, policyQualifierInfo,
932                      policyQualifierInfoLen * sizeof(WCHAR));
933                     str += policyQualifierInfoLen;
934                 }
935                 charsNeeded += headingSepLen;
936                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
937                 {
938                     lstrcpyW(str, headingSep);
939                     str += headingSepLen;
940                 }
941                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
942                 {
943                     charsNeeded += 2 * lstrlenW(indent);
944                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
945                     {
946                         lstrcpyW(str, indent);
947                         str += lstrlenW(indent);
948                         lstrcpyW(str, indent);
949                         str += lstrlenW(indent);
950                     }
951                 }
952                 charsNeeded += policyQualifierIdLen;
953                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
954                 {
955                     memcpy(str, policyQualifierId,
956                      policyQualifierIdLen * sizeof(WCHAR));
957                     str += policyQualifierIdLen;
958                 }
959                 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
960                  szOID_PKIX_POLICY_QUALIFIER_CPS))
961                 {
962                     charsNeeded += cpsLen;
963                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
964                     {
965                         memcpy(str, cps, cpsLen * sizeof(WCHAR));
966                         str += cpsLen;
967                     }
968                 }
969                 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
970                  szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
971                 {
972                     charsNeeded += userNoticeLen;
973                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
974                     {
975                         memcpy(str, userNotice, userNoticeLen * sizeof(WCHAR));
976                         str += userNoticeLen;
977                     }
978                 }
979                 else
980                 {
981                     charsNeeded += strlen(qualifierInfo->pszPolicyQualifierId);
982                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
983                     {
984                         for (src = qualifierInfo->pszPolicyQualifierId;
985                          src && *src; src++, str++)
986                             *str = *src;
987                     }
988                 }
989                 charsNeeded += sepLen;
990                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
991                 {
992                     lstrcpyW(str, sep);
993                     str += sepLen;
994                 }
995                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
996                 {
997                     charsNeeded += 2 * lstrlenW(indent);
998                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
999                     {
1000                         lstrcpyW(str, indent);
1001                         str += lstrlenW(indent);
1002                         lstrcpyW(str, indent);
1003                         str += lstrlenW(indent);
1004                     }
1005                 }
1006                 charsNeeded += qualifierLen;
1007                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1008                 {
1009                     memcpy(str, qualifier, qualifierLen * sizeof(WCHAR));
1010                     str += qualifierLen;
1011                 }
1012                 charsNeeded += headingSepLen;
1013                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1014                 {
1015                     lstrcpyW(str, headingSep);
1016                     str += headingSepLen;
1017                 }
1018                 /* This if block is deliberately redundant with the same if
1019                  * block above, in order to keep the code more readable (the
1020                  * code flow follows the order in which the strings are output.)
1021                  */
1022                 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1023                  szOID_PKIX_POLICY_QUALIFIER_CPS))
1024                 {
1025                     if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1026                     {
1027                         /* Insufficient space, determine how much is needed. */
1028                         ret = CRYPT_FormatCPS(dwCertEncodingType,
1029                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1030                          qualifierInfo->Qualifier.cbData, NULL, &size);
1031                         if (ret)
1032                             charsNeeded += size - 1;
1033                     }
1034                     else
1035                     {
1036                         sizeRemaining = *pcbFormat / sizeof(WCHAR);
1037                         sizeRemaining -= str - (LPWSTR)pbFormat;
1038                         ret = CRYPT_FormatCPS(dwCertEncodingType,
1039                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1040                          qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1041                         if (ret || GetLastError() == ERROR_MORE_DATA)
1042                         {
1043                             charsNeeded += sizeRemaining - 1;
1044                             str += sizeRemaining - 1;
1045                         }
1046                     }
1047                 }
1048                 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1049                  szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
1050                 {
1051                     if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1052                     {
1053                         /* Insufficient space, determine how much is needed. */
1054                         ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1055                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1056                          qualifierInfo->Qualifier.cbData, NULL, &size);
1057                         if (ret)
1058                             charsNeeded += size - 1;
1059                     }
1060                     else
1061                     {
1062                         sizeRemaining = *pcbFormat / sizeof(WCHAR);
1063                         sizeRemaining -= str - (LPWSTR)pbFormat;
1064                         ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1065                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1066                          qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1067                         if (ret || GetLastError() == ERROR_MORE_DATA)
1068                         {
1069                             charsNeeded += sizeRemaining - 1;
1070                             str += sizeRemaining - 1;
1071                         }
1072                     }
1073                 }
1074                 else
1075                 {
1076                     if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1077                     {
1078                         /* Insufficient space, determine how much is needed. */
1079                         ret = CRYPT_FormatHexString(
1080                          qualifierInfo->Qualifier.pbData,
1081                          qualifierInfo->Qualifier.cbData, NULL, &size);
1082                         if (ret)
1083                             charsNeeded += size - 1;
1084                     }
1085                     else
1086                     {
1087                         sizeRemaining = *pcbFormat / sizeof(WCHAR);
1088                         sizeRemaining -= str - (LPWSTR)pbFormat;
1089                         ret = CRYPT_FormatHexString(
1090                          qualifierInfo->Qualifier.pbData,
1091                          qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1092                         if (ret || GetLastError() == ERROR_MORE_DATA)
1093                         {
1094                             charsNeeded += sizeRemaining - 1;
1095                             str += sizeRemaining - 1;
1096                         }
1097                     }
1098                 }
1099             }
1100         }
1101         LocalFree(policies);
1102         if (ret)
1103         {
1104             if (!pbFormat)
1105                 *pcbFormat = charsNeeded * sizeof(WCHAR);
1106             else if (*pcbFormat < charsNeeded * sizeof(WCHAR))
1107             {
1108                 *pcbFormat = charsNeeded * sizeof(WCHAR);
1109                 SetLastError(ERROR_MORE_DATA);
1110                 ret = FALSE;
1111             }
1112             else
1113                 *pcbFormat = charsNeeded * sizeof(WCHAR);
1114         }
1115     }
1116     return ret;
1117 }
1118 
1119 #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4"
1120 
1121 /***********************************************************************
1122  *		DllRegisterServer (CRYPTDLG.@)
1123  */
1124 HRESULT WINAPI DllRegisterServer(void)
1125 {
1126     static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
1127      'd','l','l',0 };
1128     static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
1129      'd','l','l',0 };
1130     static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
1131      'I','n','i','t',0 };
1132     static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
1133      'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
1134     static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
1135      'C','e','r','t','P','o','l','i','c','y',0 };
1136     static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
1137      'F','i','n','a','l','P','o','l','i','c','y',0 };
1138     static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
1139      'C','l','e','a','n','u','p',0 };
1140     static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.',
1141        'd','l','l',0 };
1142     CRYPT_REGISTER_ACTIONID reg;
1143     GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1144     HRESULT hr = S_OK;
1145 
1146     memset(&reg, 0, sizeof(reg));
1147     reg.cbStruct = sizeof(reg);
1148     reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1149     reg.sInitProvider.pwszDLLName = cryptdlg;
1150     reg.sInitProvider.pwszFunctionName = certTrustInit;
1151     reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1152     reg.sCertificateProvider.pwszDLLName = wintrust;
1153     reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
1154     reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1155     reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
1156     reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
1157     reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1158     reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
1159     reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
1160     reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1161     reg.sCleanupProvider.pwszDLLName = cryptdlg;
1162     reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
1163     if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
1164         hr = GetLastError();
1165     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1166      "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence");
1167     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1168      szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID");
1169     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1170      "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence");
1171     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1172      szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID");
1173     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1174      szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection");
1175     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1176      szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension");
1177     return hr;
1178 }
1179 
1180 /***********************************************************************
1181  *		DllUnregisterServer (CRYPTDLG.@)
1182  */
1183 HRESULT WINAPI DllUnregisterServer(void)
1184 {
1185     GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1186 
1187     WintrustRemoveActionID(&guid);
1188     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1189      "1.3.6.1.4.1.311.16.1.1");
1190     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1191      szOID_MICROSOFT_Encryption_Key_Preference);
1192     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1193      "1.3.6.1.4.1.311.16.1.1");
1194     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1195      szOID_MICROSOFT_Encryption_Key_Preference);
1196     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1197      szOID_PKIX_KP_EMAIL_PROTECTION);
1198     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1199      szOID_CERT_POLICIES);
1200     return S_OK;
1201 }
1202