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