rpcrt4: Don't try to bind to a null handle.
[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 sep;
538         DWORD sepLen;
539
540         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
541             sep = crlf;
542         else
543             sep = commaSep;
544
545         sepLen = strlenW(sep);
546
547         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
548         {
549             charsNeeded += 3 * strlenW(indent);
550             if (str && *pcchStr >= charsNeeded)
551             {
552                 strcpyW(str, indent);
553                 str += strlenW(indent);
554                 strcpyW(str, indent);
555                 str += strlenW(indent);
556                 strcpyW(str, indent);
557                 str += strlenW(indent);
558             }
559         }
560         charsNeeded += cpsValue->Value.cbData / sizeof(WCHAR);
561         if (str && *pcchStr >= charsNeeded)
562         {
563             strcpyW(str, (LPWSTR)cpsValue->Value.pbData);
564             str += cpsValue->Value.cbData / sizeof(WCHAR);
565         }
566         charsNeeded += sepLen;
567         if (str && *pcchStr >= charsNeeded)
568         {
569             strcpyW(str, sep);
570             str += sepLen;
571         }
572         LocalFree(cpsValue);
573         if (!str)
574             *pcchStr = charsNeeded;
575         else if (*pcchStr < charsNeeded)
576         {
577             *pcchStr = charsNeeded;
578             SetLastError(ERROR_MORE_DATA);
579             ret = FALSE;
580         }
581         else
582             *pcchStr = charsNeeded;
583     }
584     return ret;
585 }
586
587 static BOOL CRYPT_FormatUserNotice(DWORD dwCertEncodingType,
588  DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
589  WCHAR *str, DWORD *pcchStr)
590 {
591     BOOL ret;
592     DWORD size, charsNeeded = 1;
593     CERT_POLICY_QUALIFIER_USER_NOTICE *notice;
594
595     if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
596      X509_PKIX_POLICY_QUALIFIER_USERNOTICE, pbEncoded, cbEncoded,
597      CRYPT_DECODE_ALLOC_FLAG, NULL, &notice, &size)))
598     {
599         static const WCHAR numFmt[] = { '%','d',0 };
600         CERT_POLICY_QUALIFIER_NOTICE_REFERENCE *pNoticeRef =
601          notice->pNoticeReference;
602         LPCWSTR headingSep, sep;
603         DWORD headingSepLen, sepLen;
604         LPWSTR noticeRef, organization, noticeNum, noticeText;
605         DWORD noticeRefLen, organizationLen, noticeNumLen, noticeTextLen;
606         WCHAR noticeNumStr[11];
607
608         noticeRefLen = LoadStringW(hInstance, IDS_NOTICE_REF,
609          (LPWSTR)&noticeRef, 0);
610         organizationLen = LoadStringW(hInstance, IDS_ORGANIZATION,
611          (LPWSTR)&organization, 0);
612         noticeNumLen = LoadStringW(hInstance, IDS_NOTICE_NUM,
613          (LPWSTR)&noticeNum, 0);
614         noticeTextLen = LoadStringW(hInstance, IDS_NOTICE_TEXT,
615          (LPWSTR)&noticeText, 0);
616         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
617         {
618             headingSep = colonCrlf;
619             sep = crlf;
620         }
621         else
622         {
623             headingSep = colonSpace;
624             sep = commaSep;
625         }
626         sepLen = strlenW(sep);
627         headingSepLen = strlenW(headingSep);
628
629         if (pNoticeRef)
630         {
631             DWORD k;
632             LPCSTR src;
633
634             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
635             {
636                 charsNeeded += 3 * strlenW(indent);
637                 if (str && *pcchStr >= charsNeeded)
638                 {
639                     strcpyW(str, indent);
640                     str += strlenW(indent);
641                     strcpyW(str, indent);
642                     str += strlenW(indent);
643                     strcpyW(str, indent);
644                     str += strlenW(indent);
645                 }
646             }
647             charsNeeded += noticeRefLen;
648             if (str && *pcchStr >= charsNeeded)
649             {
650                 memcpy(str, noticeRef, noticeRefLen * sizeof(WCHAR));
651                 str += noticeRefLen;
652             }
653             charsNeeded += headingSepLen;
654             if (str && *pcchStr >= charsNeeded)
655             {
656                 strcpyW(str, headingSep);
657                 str += headingSepLen;
658             }
659             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
660             {
661                 charsNeeded += 4 * strlenW(indent);
662                 if (str && *pcchStr >= charsNeeded)
663                 {
664                     strcpyW(str, indent);
665                     str += strlenW(indent);
666                     strcpyW(str, indent);
667                     str += strlenW(indent);
668                     strcpyW(str, indent);
669                     str += strlenW(indent);
670                     strcpyW(str, indent);
671                     str += strlenW(indent);
672                 }
673             }
674             charsNeeded += organizationLen;
675             if (str && *pcchStr >= charsNeeded)
676             {
677                 memcpy(str, organization, organizationLen * sizeof(WCHAR));
678                 str += organizationLen;
679             }
680             charsNeeded += strlen(pNoticeRef->pszOrganization);
681             if (str && *pcchStr >= charsNeeded)
682                 for (src = pNoticeRef->pszOrganization; src && *src;
683                  src++, str++)
684                     *str = *src;
685             charsNeeded += sepLen;
686             if (str && *pcchStr >= charsNeeded)
687             {
688                 strcpyW(str, sep);
689                 str += sepLen;
690             }
691             for (k = 0; k < pNoticeRef->cNoticeNumbers; k++)
692             {
693                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
694                 {
695                     charsNeeded += 4 * strlenW(indent);
696                     if (str && *pcchStr >= charsNeeded)
697                     {
698                         strcpyW(str, indent);
699                         str += strlenW(indent);
700                         strcpyW(str, indent);
701                         str += strlenW(indent);
702                         strcpyW(str, indent);
703                         str += strlenW(indent);
704                         strcpyW(str, indent);
705                         str += strlenW(indent);
706                     }
707                 }
708                 charsNeeded += noticeNumLen;
709                 if (str && *pcchStr >= charsNeeded)
710                 {
711                     memcpy(str, noticeNum, noticeNumLen * sizeof(WCHAR));
712                     str += noticeNumLen;
713                 }
714                 sprintfW(noticeNumStr, numFmt, k + 1);
715                 charsNeeded += strlenW(noticeNumStr);
716                 if (str && *pcchStr >= charsNeeded)
717                 {
718                     strcpyW(str, noticeNumStr);
719                     str += strlenW(noticeNumStr);
720                 }
721                 charsNeeded += sepLen;
722                 if (str && *pcchStr >= charsNeeded)
723                 {
724                     strcpyW(str, sep);
725                     str += sepLen;
726                 }
727             }
728         }
729         if (notice->pszDisplayText)
730         {
731             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
732             {
733                 charsNeeded += 3 * strlenW(indent);
734                 if (str && *pcchStr >= charsNeeded)
735                 {
736                     strcpyW(str, indent);
737                     str += strlenW(indent);
738                     strcpyW(str, indent);
739                     str += strlenW(indent);
740                     strcpyW(str, indent);
741                     str += strlenW(indent);
742                 }
743             }
744             charsNeeded += noticeTextLen;
745             if (str && *pcchStr >= charsNeeded)
746             {
747                 memcpy(str, noticeText, noticeTextLen * sizeof(WCHAR));
748                 str += noticeTextLen;
749             }
750             charsNeeded += strlenW(notice->pszDisplayText);
751             if (str && *pcchStr >= charsNeeded)
752             {
753                 strcpyW(str, notice->pszDisplayText);
754                 str += strlenW(notice->pszDisplayText);
755             }
756             charsNeeded += sepLen;
757             if (str && *pcchStr >= charsNeeded)
758             {
759                 strcpyW(str, sep);
760                 str += sepLen;
761             }
762         }
763         LocalFree(notice);
764         if (!str)
765             *pcchStr = charsNeeded;
766         else if (*pcchStr < charsNeeded)
767         {
768             *pcchStr = charsNeeded;
769             SetLastError(ERROR_MORE_DATA);
770             ret = FALSE;
771         }
772         else
773             *pcchStr = charsNeeded;
774     }
775     return ret;
776 }
777
778 /***********************************************************************
779  *              FormatVerisignExtension (CRYPTDLG.@)
780  */
781 BOOL WINAPI FormatVerisignExtension(DWORD dwCertEncodingType,
782  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
783  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
784  DWORD *pcbFormat)
785 {
786     CERT_POLICIES_INFO *policies;
787     DWORD size;
788     BOOL ret = FALSE;
789
790     if (!cbEncoded)
791     {
792         SetLastError(E_INVALIDARG);
793         return FALSE;
794     }
795     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_POLICIES,
796      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size)))
797     {
798         static const WCHAR numFmt[] = { '%','d',0 };
799         DWORD charsNeeded = 1; /* space for NULL terminator */
800         LPCWSTR headingSep, sep;
801         DWORD headingSepLen, sepLen;
802         WCHAR policyNum[11], policyQualifierNum[11];
803         LPWSTR certPolicy, policyId, policyQualifierInfo, policyQualifierId;
804         LPWSTR cps, userNotice, qualifier;
805         DWORD certPolicyLen, policyIdLen, policyQualifierInfoLen;
806         DWORD policyQualifierIdLen, cpsLen, userNoticeLen, qualifierLen;
807         DWORD i;
808         LPWSTR str = pbFormat;
809
810         certPolicyLen = LoadStringW(hInstance, IDS_CERT_POLICY,
811          (LPWSTR)&certPolicy, 0);
812         policyIdLen = LoadStringW(hInstance, IDS_POLICY_ID, (LPWSTR)&policyId,
813          0);
814         policyQualifierInfoLen = LoadStringW(hInstance,
815          IDS_POLICY_QUALIFIER_INFO, (LPWSTR)&policyQualifierInfo, 0);
816         policyQualifierIdLen = LoadStringW(hInstance, IDS_POLICY_QUALIFIER_ID,
817          (LPWSTR)&policyQualifierId, 0);
818         cpsLen = LoadStringW(hInstance, IDS_CPS, (LPWSTR)&cps, 0);
819         userNoticeLen = LoadStringW(hInstance, IDS_USER_NOTICE,
820          (LPWSTR)&userNotice, 0);
821         qualifierLen = LoadStringW(hInstance, IDS_QUALIFIER,
822          (LPWSTR)&qualifier, 0);
823         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
824         {
825             headingSep = colonCrlf;
826             sep = crlf;
827         }
828         else
829         {
830             headingSep = colonSpace;
831             sep = commaSep;
832         }
833         sepLen = strlenW(sep);
834         headingSepLen = strlenW(headingSep);
835
836         for (i = 0; ret && i < policies->cPolicyInfo; i++)
837         {
838             CERT_POLICY_INFO *policy = &policies->rgPolicyInfo[i];
839             DWORD j;
840             LPCSTR src;
841
842             charsNeeded += 1; /* '['*/
843             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
844                 *str++ = '[';
845             sprintfW(policyNum, numFmt, i + 1);
846             charsNeeded += strlenW(policyNum);
847             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
848             {
849                 strcpyW(str, policyNum);
850                 str += strlenW(policyNum);
851             }
852             charsNeeded += 1; /* ']'*/
853             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
854                 *str++ = ']';
855             charsNeeded += certPolicyLen;
856             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
857             {
858                 memcpy(str, certPolicy, certPolicyLen * sizeof(WCHAR));
859                 str += certPolicyLen;
860             }
861             charsNeeded += headingSepLen;
862             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
863             {
864                 strcpyW(str, headingSep);
865                 str += headingSepLen;
866             }
867             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
868             {
869                 charsNeeded += strlenW(indent);
870                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
871                 {
872                     strcpyW(str, indent);
873                     str += strlenW(indent);
874                 }
875             }
876             charsNeeded += policyIdLen;
877             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
878             {
879                 memcpy(str, policyId, policyIdLen * sizeof(WCHAR));
880                 str += policyIdLen;
881             }
882             charsNeeded += strlen(policy->pszPolicyIdentifier);
883             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
884             {
885                 for (src = policy->pszPolicyIdentifier; src && *src;
886                  src++, str++)
887                     *str = *src;
888             }
889             charsNeeded += sepLen;
890             if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
891             {
892                 strcpyW(str, sep);
893                 str += sepLen;
894             }
895             for (j = 0; j < policy->cPolicyQualifier; j++)
896             {
897                 CERT_POLICY_QUALIFIER_INFO *qualifierInfo =
898                  &policy->rgPolicyQualifier[j];
899                 DWORD sizeRemaining;
900
901                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
902                 {
903                     charsNeeded += strlenW(indent);
904                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
905                     {
906                         strcpyW(str, indent);
907                         str += strlenW(indent);
908                     }
909                 }
910                 charsNeeded += 1; /* '['*/
911                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
912                     *str++ = '[';
913                 charsNeeded += strlenW(policyNum);
914                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
915                 {
916                     strcpyW(str, policyNum);
917                     str += strlenW(policyNum);
918                 }
919                 charsNeeded += 1; /* ','*/
920                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
921                     *str++ = ',';
922                 sprintfW(policyQualifierNum, numFmt, j + 1);
923                 charsNeeded += strlenW(policyQualifierNum);
924                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
925                 {
926                     strcpyW(str, policyQualifierNum);
927                     str += strlenW(policyQualifierNum);
928                 }
929                 charsNeeded += 1; /* ']'*/
930                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
931                     *str++ = ']';
932                 charsNeeded += policyQualifierInfoLen;
933                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
934                 {
935                     memcpy(str, policyQualifierInfo,
936                      policyQualifierInfoLen * sizeof(WCHAR));
937                     str += policyQualifierInfoLen;
938                 }
939                 charsNeeded += headingSepLen;
940                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
941                 {
942                     strcpyW(str, headingSep);
943                     str += headingSepLen;
944                 }
945                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
946                 {
947                     charsNeeded += 2 * strlenW(indent);
948                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
949                     {
950                         strcpyW(str, indent);
951                         str += strlenW(indent);
952                         strcpyW(str, indent);
953                         str += strlenW(indent);
954                     }
955                 }
956                 charsNeeded += policyQualifierIdLen;
957                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
958                 {
959                     memcpy(str, policyQualifierId,
960                      policyQualifierIdLen * sizeof(WCHAR));
961                     str += policyQualifierIdLen;
962                 }
963                 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
964                  szOID_PKIX_POLICY_QUALIFIER_CPS))
965                 {
966                     charsNeeded += cpsLen;
967                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
968                     {
969                         memcpy(str, cps, cpsLen * sizeof(WCHAR));
970                         str += cpsLen;
971                     }
972                 }
973                 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
974                  szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
975                 {
976                     charsNeeded += userNoticeLen;
977                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
978                     {
979                         memcpy(str, userNotice, userNoticeLen * sizeof(WCHAR));
980                         str += userNoticeLen;
981                     }
982                 }
983                 else
984                 {
985                     charsNeeded += strlen(qualifierInfo->pszPolicyQualifierId);
986                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
987                     {
988                         for (src = qualifierInfo->pszPolicyQualifierId;
989                          src && *src; src++, str++)
990                             *str = *src;
991                     }
992                 }
993                 charsNeeded += sepLen;
994                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
995                 {
996                     strcpyW(str, sep);
997                     str += sepLen;
998                 }
999                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1000                 {
1001                     charsNeeded += 2 * strlenW(indent);
1002                     if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1003                     {
1004                         strcpyW(str, indent);
1005                         str += strlenW(indent);
1006                         strcpyW(str, indent);
1007                         str += strlenW(indent);
1008                     }
1009                 }
1010                 charsNeeded += qualifierLen;
1011                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1012                 {
1013                     memcpy(str, qualifier, qualifierLen * sizeof(WCHAR));
1014                     str += qualifierLen;
1015                 }
1016                 charsNeeded += headingSepLen;
1017                 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1018                 {
1019                     strcpyW(str, headingSep);
1020                     str += headingSepLen;
1021                 }
1022                 /* This if block is deliberately redundant with the same if
1023                  * block above, in order to keep the code more readable (the
1024                  * code flow follows the order in which the strings are output.)
1025                  */
1026                 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1027                  szOID_PKIX_POLICY_QUALIFIER_CPS))
1028                 {
1029                     if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1030                     {
1031                         /* Insufficient space, determine how much is needed. */
1032                         ret = CRYPT_FormatCPS(dwCertEncodingType,
1033                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1034                          qualifierInfo->Qualifier.cbData, NULL, &size);
1035                         if (ret)
1036                             charsNeeded += size - 1;
1037                     }
1038                     else
1039                     {
1040                         sizeRemaining = *pcbFormat / sizeof(WCHAR);
1041                         sizeRemaining -= str - (LPWSTR)pbFormat;
1042                         ret = CRYPT_FormatCPS(dwCertEncodingType,
1043                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1044                          qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1045                         if (ret || GetLastError() == ERROR_MORE_DATA)
1046                         {
1047                             charsNeeded += sizeRemaining - 1;
1048                             str += sizeRemaining - 1;
1049                         }
1050                     }
1051                 }
1052                 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1053                  szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
1054                 {
1055                     if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1056                     {
1057                         /* Insufficient space, determine how much is needed. */
1058                         ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1059                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1060                          qualifierInfo->Qualifier.cbData, NULL, &size);
1061                         if (ret)
1062                             charsNeeded += size - 1;
1063                     }
1064                     else
1065                     {
1066                         sizeRemaining = *pcbFormat / sizeof(WCHAR);
1067                         sizeRemaining -= str - (LPWSTR)pbFormat;
1068                         ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1069                          dwFormatStrType, qualifierInfo->Qualifier.pbData,
1070                          qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1071                         if (ret || GetLastError() == ERROR_MORE_DATA)
1072                         {
1073                             charsNeeded += sizeRemaining - 1;
1074                             str += sizeRemaining - 1;
1075                         }
1076                     }
1077                 }
1078                 else
1079                 {
1080                     if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1081                     {
1082                         /* Insufficient space, determine how much is needed. */
1083                         ret = CRYPT_FormatHexString(
1084                          qualifierInfo->Qualifier.pbData,
1085                          qualifierInfo->Qualifier.cbData, NULL, &size);
1086                         if (ret)
1087                             charsNeeded += size - 1;
1088                     }
1089                     else
1090                     {
1091                         sizeRemaining = *pcbFormat / sizeof(WCHAR);
1092                         sizeRemaining -= str - (LPWSTR)pbFormat;
1093                         ret = CRYPT_FormatHexString(
1094                          qualifierInfo->Qualifier.pbData,
1095                          qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1096                         if (ret || GetLastError() == ERROR_MORE_DATA)
1097                         {
1098                             charsNeeded += sizeRemaining - 1;
1099                             str += sizeRemaining - 1;
1100                         }
1101                     }
1102                 }
1103             }
1104         }
1105         LocalFree(policies);
1106         if (ret)
1107         {
1108             if (!pbFormat)
1109                 *pcbFormat = charsNeeded * sizeof(WCHAR);
1110             else if (*pcbFormat < charsNeeded * sizeof(WCHAR))
1111             {
1112                 *pcbFormat = charsNeeded * sizeof(WCHAR);
1113                 SetLastError(ERROR_MORE_DATA);
1114                 ret = FALSE;
1115             }
1116             else
1117                 *pcbFormat = charsNeeded * sizeof(WCHAR);
1118         }
1119     }
1120     return ret;
1121 }
1122
1123 #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4"
1124
1125 /***********************************************************************
1126  *              DllRegisterServer (CRYPTDLG.@)
1127  */
1128 HRESULT WINAPI DllRegisterServer(void)
1129 {
1130     static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
1131      'd','l','l',0 };
1132     static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
1133      'd','l','l',0 };
1134     static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
1135      'I','n','i','t',0 };
1136     static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
1137      'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
1138     static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
1139      'C','e','r','t','P','o','l','i','c','y',0 };
1140     static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
1141      'F','i','n','a','l','P','o','l','i','c','y',0 };
1142     static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
1143      'C','l','e','a','n','u','p',0 };
1144     static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.',
1145        'd','l','l',0 };
1146     CRYPT_REGISTER_ACTIONID reg;
1147     GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1148     HRESULT hr = S_OK;
1149
1150     memset(&reg, 0, sizeof(reg));
1151     reg.cbStruct = sizeof(reg);
1152     reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1153     reg.sInitProvider.pwszDLLName = cryptdlg;
1154     reg.sInitProvider.pwszFunctionName = certTrustInit;
1155     reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1156     reg.sCertificateProvider.pwszDLLName = wintrust;
1157     reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
1158     reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1159     reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
1160     reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
1161     reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1162     reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
1163     reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
1164     reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1165     reg.sCleanupProvider.pwszDLLName = cryptdlg;
1166     reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
1167     if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
1168         hr = GetLastError();
1169     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1170      "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence");
1171     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1172      szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID");
1173     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1174      "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence");
1175     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1176      szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID");
1177     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1178      szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection");
1179     CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1180      szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension");
1181     return hr;
1182 }
1183
1184 /***********************************************************************
1185  *              DllUnregisterServer (CRYPTDLG.@)
1186  */
1187 HRESULT WINAPI DllUnregisterServer(void)
1188 {
1189     GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1190
1191     WintrustRemoveActionID(&guid);
1192     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1193      "1.3.6.1.4.1.311.16.1.1");
1194     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1195      szOID_MICROSOFT_Encryption_Key_Preference);
1196     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1197      "1.3.6.1.4.1.311.16.1.1");
1198     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1199      szOID_MICROSOFT_Encryption_Key_Preference);
1200     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1201      szOID_PKIX_KP_EMAIL_PROTECTION);
1202     CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1203      szOID_CERT_POLICIES);
1204     return S_OK;
1205 }