d3dx8: Add a few tests for MatrixStack.
[wine] / dlls / crypt32 / object.c
1 /*
2  * crypt32 Crypt*Object functions
3  *
4  * Copyright 2007 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21 #define NONAMELESSUNION
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wincrypt.h"
25 #include "mssip.h"
26 #include "winuser.h"
27 #include "wintrust.h"
28 #include "crypt32_private.h"
29 #include "cryptres.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
34
35 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
36 {
37     BOOL ret = FALSE;
38     HANDLE file;
39
40     TRACE("%s\n", debugstr_w(fileName));
41
42     file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
43      OPEN_EXISTING, 0, NULL);
44     if (file != INVALID_HANDLE_VALUE)
45     {
46         ret = TRUE;
47         blob->cbData = GetFileSize(file, NULL);
48         if (blob->cbData)
49         {
50             blob->pbData = CryptMemAlloc(blob->cbData);
51             if (blob->pbData)
52             {
53                 DWORD read;
54
55                 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
56             }
57         }
58         CloseHandle(file);
59     }
60     TRACE("returning %d\n", ret);
61     return ret;
62 }
63
64 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
65  DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
66  DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
67 {
68     CERT_BLOB fileBlob;
69     const CERT_BLOB *blob;
70     HCERTSTORE store;
71     DWORD contentType;
72     BOOL ret;
73
74     switch (dwObjectType)
75     {
76     case CERT_QUERY_OBJECT_FILE:
77         /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
78          * just read the file directly
79          */
80         ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
81         blob = &fileBlob;
82         break;
83     case CERT_QUERY_OBJECT_BLOB:
84         blob = (const CERT_BLOB *)pvObject;
85         ret = TRUE;
86         break;
87     default:
88         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
89         ret = FALSE;
90     }
91     if (!ret)
92         return FALSE;
93
94     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
95      CERT_STORE_CREATE_NEW_FLAG, NULL);
96     ret = FALSE;
97     if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
98     {
99         ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
100          blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
101         if (ret)
102             contentType = CERT_QUERY_CONTENT_CERT;
103     }
104     if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
105     {
106         ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
107          blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
108         if (ret)
109             contentType = CERT_QUERY_CONTENT_CRL;
110     }
111     if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
112     {
113         ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
114          blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
115         if (ret)
116             contentType = CERT_QUERY_CONTENT_CTL;
117     }
118     if (ret)
119     {
120         if (pdwMsgAndCertEncodingType)
121             *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
122         if (pdwContentType)
123             *pdwContentType = contentType;
124         if (phCertStore)
125             *phCertStore = CertDuplicateStore(store);
126     }
127     CertCloseStore(store, 0);
128     if (blob == &fileBlob)
129         CryptMemFree(blob->pbData);
130     TRACE("returning %d\n", ret);
131     return ret;
132 }
133
134 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
135  const void *pvObject, DWORD dwExpectedContentTypeFlags,
136  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
137  HCERTSTORE *phCertStore, const void **ppvContext)
138 {
139     CERT_BLOB fileBlob;
140     const CERT_BLOB *blob;
141     const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
142     const void *context;
143     DWORD contextType;
144     BOOL ret;
145
146     switch (dwObjectType)
147     {
148     case CERT_QUERY_OBJECT_FILE:
149         /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
150          * just read the file directly
151          */
152         ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
153         blob = &fileBlob;
154         break;
155     case CERT_QUERY_OBJECT_BLOB:
156         blob = (const CERT_BLOB *)pvObject;
157         ret = TRUE;
158         break;
159     default:
160         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
161         ret = FALSE;
162     }
163     if (!ret)
164         return FALSE;
165
166     context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
167      CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
168     if (context)
169     {
170         DWORD contentType, certStoreOffset;
171
172         ret = TRUE;
173         switch (contextType)
174         {
175         case CERT_STORE_CERTIFICATE_CONTEXT:
176             contextInterface = pCertInterface;
177             contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
178             certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
179             if (!(dwExpectedContentTypeFlags &
180              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
181             {
182                 SetLastError(ERROR_INVALID_DATA);
183                 ret = FALSE;
184                 goto end;
185             }
186             break;
187         case CERT_STORE_CRL_CONTEXT:
188             contextInterface = pCRLInterface;
189             contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
190             certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
191             if (!(dwExpectedContentTypeFlags &
192              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
193             {
194                 SetLastError(ERROR_INVALID_DATA);
195                 ret = FALSE;
196                 goto end;
197             }
198             break;
199         case CERT_STORE_CTL_CONTEXT:
200             contextInterface = pCTLInterface;
201             contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
202             certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
203             if (!(dwExpectedContentTypeFlags &
204              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
205             {
206                 SetLastError(ERROR_INVALID_DATA);
207                 ret = FALSE;
208                 goto end;
209             }
210             break;
211         default:
212             SetLastError(ERROR_INVALID_DATA);
213             ret = FALSE;
214             goto end;
215         }
216         if (pdwMsgAndCertEncodingType)
217             *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
218         if (pdwContentType)
219             *pdwContentType = contentType;
220         if (phCertStore)
221             *phCertStore = CertDuplicateStore(
222              *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
223         if (ppvContext)
224             *ppvContext = contextInterface->duplicate(context);
225     }
226
227 end:
228     if (contextInterface && context)
229         contextInterface->free(context);
230     if (blob == &fileBlob)
231         CryptMemFree(blob->pbData);
232     TRACE("returning %d\n", ret);
233     return ret;
234 }
235
236 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
237  const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
238  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
239 {
240     LPCWSTR fileName = (LPCWSTR)pvObject;
241     HANDLE file;
242     BOOL ret = FALSE;
243
244     if (dwObjectType != CERT_QUERY_OBJECT_FILE)
245     {
246         FIXME("unimplemented for non-file type %d\n", dwObjectType);
247         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
248         return FALSE;
249     }
250     TRACE("%s\n", debugstr_w(fileName));
251     file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
252      OPEN_EXISTING, 0, NULL);
253     if (file != INVALID_HANDLE_VALUE)
254     {
255         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
256          CERT_STORE_CREATE_NEW_FLAG, NULL);
257
258         ret = CRYPT_ReadSerializedStoreFromFile(file, store);
259         if (ret)
260         {
261             if (pdwMsgAndCertEncodingType)
262                 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
263             if (pdwContentType)
264                 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
265             if (phCertStore)
266                 *phCertStore = CertDuplicateStore(store);
267         }
268         CertCloseStore(store, 0);
269         CloseHandle(file);
270     }
271     TRACE("returning %d\n", ret);
272     return ret;
273 }
274
275 /* Used to decode non-embedded messages */
276 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
277  DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
278  DWORD *pdwContentType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
279 {
280     CERT_BLOB fileBlob;
281     const CERT_BLOB *blob;
282     BOOL ret;
283     HCRYPTMSG msg = NULL;
284     DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
285
286     switch (dwObjectType)
287     {
288     case CERT_QUERY_OBJECT_FILE:
289         /* This isn't an embedded PKCS7 message, so just read the file
290          * directly
291          */
292         ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
293         blob = &fileBlob;
294         break;
295     case CERT_QUERY_OBJECT_BLOB:
296         blob = (const CERT_BLOB *)pvObject;
297         ret = TRUE;
298         break;
299     default:
300         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
301         ret = FALSE;
302     }
303     if (!ret)
304         return FALSE;
305
306     ret = FALSE;
307     /* Try it first as a PKCS content info */
308     if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
309      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
310     {
311         msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL);
312         if (msg)
313         {
314             ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
315             if (ret)
316             {
317                 DWORD type, len = sizeof(type);
318
319                 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
320                 if (ret)
321                 {
322                     if ((dwExpectedContentTypeFlags &
323                      CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
324                     {
325                         if (type != CMSG_SIGNED)
326                         {
327                             SetLastError(ERROR_INVALID_DATA);
328                             ret = FALSE;
329                         }
330                         else if (pdwContentType)
331                             *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
332                     }
333                     else if ((dwExpectedContentTypeFlags &
334                      CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
335                     {
336                         if (type != CMSG_DATA)
337                         {
338                             SetLastError(ERROR_INVALID_DATA);
339                             ret = FALSE;
340                         }
341                         else if (pdwContentType)
342                             *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
343                     }
344                 }
345             }
346             if (!ret)
347             {
348                 CryptMsgClose(msg);
349                 msg = NULL;
350             }
351         }
352     }
353     /* Failing that, try explicitly typed messages */
354     if (!ret &&
355      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
356     {
357         msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
358         if (msg)
359         {
360             ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
361             if (!ret)
362             {
363                 CryptMsgClose(msg);
364                 msg = NULL;
365             }
366         }
367         if (msg && pdwContentType)
368             *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
369     }
370     if (!ret &&
371      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
372     {
373         msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
374         if (msg)
375         {
376             ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
377             if (!ret)
378             {
379                 CryptMsgClose(msg);
380                 msg = NULL;
381             }
382         }
383         if (msg && pdwContentType)
384             *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
385     }
386     if (pdwMsgAndCertEncodingType)
387         *pdwMsgAndCertEncodingType = encodingType;
388     if (msg)
389     {
390         if (phMsg)
391             *phMsg = msg;
392         if (phCertStore)
393             *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
394              0, msg);
395     }
396     if (blob == &fileBlob)
397         CryptMemFree(blob->pbData);
398     TRACE("returning %d\n", ret);
399     return ret;
400 }
401
402 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
403  const void *pvObject, DWORD dwExpectedContentTypeFlags,
404  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
405  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
406 {
407     HANDLE file;
408     GUID subject;
409     BOOL ret = FALSE;
410
411     TRACE("%s\n", debugstr_w((LPCWSTR)pvObject));
412
413     if (dwObjectType != CERT_QUERY_OBJECT_FILE)
414     {
415         FIXME("don't know what to do for type %d embedded signed messages\n",
416          dwObjectType);
417         SetLastError(E_INVALIDARG);
418         return FALSE;
419     }
420     file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ,
421      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
422     if (file != INVALID_HANDLE_VALUE)
423     {
424         ret = CryptSIPRetrieveSubjectGuid((LPCWSTR)pvObject, file, &subject);
425         if (ret)
426         {
427             SIP_DISPATCH_INFO sip;
428
429             memset(&sip, 0, sizeof(sip));
430             sip.cbSize = sizeof(sip);
431             ret = CryptSIPLoad(&subject, 0, &sip);
432             if (ret)
433             {
434                 SIP_SUBJECTINFO subjectInfo;
435                 CERT_BLOB blob;
436                 DWORD encodingType;
437
438                 memset(&subjectInfo, 0, sizeof(subjectInfo));
439                 subjectInfo.cbSize = sizeof(subjectInfo);
440                 subjectInfo.pgSubjectType = &subject;
441                 subjectInfo.hFile = file;
442                 subjectInfo.pwsFileName = (LPCWSTR)pvObject;
443                 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
444                  NULL);
445                 if (ret)
446                 {
447                     blob.pbData = CryptMemAlloc(blob.cbData);
448                     if (blob.pbData)
449                     {
450                         ret = sip.pfGet(&subjectInfo, &encodingType, 0,
451                          &blob.cbData, blob.pbData);
452                         if (ret)
453                         {
454                             ret = CRYPT_QueryMessageObject(
455                              CERT_QUERY_OBJECT_BLOB, &blob,
456                              CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
457                              pdwMsgAndCertEncodingType, NULL, phCertStore,
458                              phMsg);
459                             if (ret && pdwContentType)
460                                 *pdwContentType =
461                                  CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
462                         }
463                         CryptMemFree(blob.pbData);
464                     }
465                     else
466                     {
467                         SetLastError(ERROR_OUTOFMEMORY);
468                         ret = FALSE;
469                     }
470                 }
471             }
472         }
473         CloseHandle(file);
474     }
475     TRACE("returning %d\n", ret);
476     return ret;
477 }
478
479 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
480  DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
481  DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
482  DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
483  const void **ppvContext)
484 {
485     static const DWORD unimplementedTypes =
486      CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
487      CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
488     BOOL ret = TRUE;
489
490     TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
491      dwObjectType, pvObject, dwExpectedContentTypeFlags,
492      dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
493      pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
494
495     if (dwExpectedContentTypeFlags & unimplementedTypes)
496         WARN("unimplemented for types %08x\n",
497          dwExpectedContentTypeFlags & unimplementedTypes);
498     if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY))
499     {
500         FIXME("unimplemented for anything but binary\n");
501         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
502         return FALSE;
503     }
504     if (pdwFormatType)
505         *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
506
507     if (phCertStore)
508         *phCertStore = NULL;
509     if (phMsg)
510         *phMsg = NULL;
511     if (ppvContext)
512         *ppvContext = NULL;
513
514     ret = FALSE;
515     if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
516      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
517      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
518     {
519         ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
520          dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
521          phCertStore, ppvContext);
522     }
523     if (!ret &&
524      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
525     {
526         ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
527          pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
528     }
529     if (!ret &&
530      ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
531      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
532      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
533     {
534         ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
535          dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
536          phCertStore, ppvContext);
537     }
538     if (!ret &&
539      ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
540      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
541     {
542         ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
543          dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
544          phCertStore, phMsg);
545     }
546     if (!ret &&
547      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
548     {
549         ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
550          dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
551          phCertStore, phMsg);
552     }
553     TRACE("returning %d\n", ret);
554     return ret;
555 }
556
557 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
558  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
559  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
560  DWORD *pcbFormat)
561 {
562     BOOL ret;
563     DWORD bytesNeeded;
564
565     if (cbEncoded)
566         bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
567     else
568         bytesNeeded = sizeof(WCHAR);
569     if (!pbFormat)
570     {
571         *pcbFormat = bytesNeeded;
572         ret = TRUE;
573     }
574     else if (*pcbFormat < bytesNeeded)
575     {
576         *pcbFormat = bytesNeeded;
577         SetLastError(ERROR_MORE_DATA);
578         ret = FALSE;
579     }
580     else
581     {
582         static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
583         static const WCHAR endFmt[] = { '%','0','2','x',0 };
584         DWORD i;
585         LPWSTR ptr = pbFormat;
586
587         *pcbFormat = bytesNeeded;
588         if (cbEncoded)
589         {
590             for (i = 0; i < cbEncoded; i++)
591             {
592                 if (i < cbEncoded - 1)
593                     ptr += sprintfW(ptr, fmt, pbEncoded[i]);
594                 else
595                     ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
596             }
597         }
598         else
599             *ptr = 0;
600         ret = TRUE;
601     }
602     return ret;
603 }
604
605 #define MAX_STRING_RESOURCE_LEN 128
606
607 static const WCHAR commaSpace[] = { ',',' ',0 };
608
609 struct BitToString
610 {
611     BYTE bit;
612     int id;
613     WCHAR str[MAX_STRING_RESOURCE_LEN];
614 };
615
616 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
617  DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
618 {
619     DWORD bytesNeeded = sizeof(WCHAR);
620     int i;
621     BOOL ret = TRUE, localFirst = *first;
622
623     for (i = 0; i < mapEntries; i++)
624         if (bits & map[i].bit)
625         {
626             if (!localFirst)
627                 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
628             localFirst = FALSE;
629             bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
630         }
631     if (!pbFormat)
632     {
633         *first = localFirst;
634         *pcbFormat = bytesNeeded;
635     }
636     else if (*pcbFormat < bytesNeeded)
637     {
638         *first = localFirst;
639         *pcbFormat = bytesNeeded;
640         SetLastError(ERROR_MORE_DATA);
641         ret = FALSE;
642     }
643     else
644     {
645         LPWSTR str = pbFormat;
646
647         localFirst = *first;
648         *pcbFormat = bytesNeeded;
649         for (i = 0; i < mapEntries; i++)
650             if (bits & map[i].bit)
651             {
652                 if (!localFirst)
653                 {
654                     strcpyW(str, commaSpace);
655                     str += strlenW(commaSpace);
656                 }
657                 localFirst = FALSE;
658                 strcpyW(str, map[i].str);
659                 str += strlenW(map[i].str);
660             }
661         *first = localFirst;
662     }
663     return ret;
664 }
665
666 static struct BitToString keyUsageByte0Map[] = {
667  { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
668  { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
669  { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
670  { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
671  { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
672  { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
673  { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
674  { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
675  { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
676 };
677 static struct BitToString keyUsageByte1Map[] = {
678  { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
679 };
680
681 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
682  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
683  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
684  DWORD *pcbFormat)
685 {
686     DWORD size;
687     CRYPT_BIT_BLOB *bits;
688     BOOL ret;
689
690     if (!cbEncoded)
691     {
692         SetLastError(E_INVALIDARG);
693         return FALSE;
694     }
695     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
696      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
697     {
698         WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
699         DWORD bytesNeeded = sizeof(WCHAR);
700
701         LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
702          sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
703         if (!bits->cbData || bits->cbData > 2)
704         {
705             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
706             if (!pbFormat)
707                 *pcbFormat = bytesNeeded;
708             else if (*pcbFormat < bytesNeeded)
709             {
710                 *pcbFormat = bytesNeeded;
711                 SetLastError(ERROR_MORE_DATA);
712                 ret = FALSE;
713             }
714             else
715             {
716                 LPWSTR str = pbFormat;
717
718                 *pcbFormat = bytesNeeded;
719                 strcpyW(str, infoNotAvailable);
720             }
721         }
722         else
723         {
724             static BOOL stringsLoaded = FALSE;
725             int i;
726             DWORD bitStringLen;
727             BOOL first = TRUE;
728
729             if (!stringsLoaded)
730             {
731                 for (i = 0;
732                  i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
733                  i++)
734                     LoadStringW(hInstance, keyUsageByte0Map[i].id,
735                      keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
736                 for (i = 0;
737                  i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
738                  i++)
739                     LoadStringW(hInstance, keyUsageByte1Map[i].id,
740                      keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
741                 stringsLoaded = TRUE;
742             }
743             CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
744              sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
745              NULL, &bitStringLen, &first);
746             bytesNeeded += bitStringLen;
747             if (bits->cbData == 2)
748             {
749                 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
750                  sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
751                  NULL, &bitStringLen, &first);
752                 bytesNeeded += bitStringLen;
753             }
754             bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
755             CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
756              bits->cbData, NULL, &size);
757             bytesNeeded += size;
758             if (!pbFormat)
759                 *pcbFormat = bytesNeeded;
760             else if (*pcbFormat < bytesNeeded)
761             {
762                 *pcbFormat = bytesNeeded;
763                 SetLastError(ERROR_MORE_DATA);
764                 ret = FALSE;
765             }
766             else
767             {
768                 LPWSTR str = pbFormat;
769
770                 bitStringLen = bytesNeeded;
771                 first = TRUE;
772                 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
773                  sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
774                  str, &bitStringLen, &first);
775                 str += bitStringLen / sizeof(WCHAR) - 1;
776                 if (bits->cbData == 2)
777                 {
778                     bitStringLen = bytesNeeded;
779                     CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
780                      sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
781                      str, &bitStringLen, &first);
782                     str += bitStringLen / sizeof(WCHAR) - 1;
783                 }
784                 *str++ = ' ';
785                 *str++ = '(';
786                 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
787                  bits->cbData, str, &size);
788                 str += size / sizeof(WCHAR) - 1;
789                 *str++ = ')';
790                 *str = 0;
791             }
792         }
793         LocalFree(bits);
794     }
795     return ret;
796 }
797
798 static const WCHAR crlf[] = { '\r','\n',0 };
799
800 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
801 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
802 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
803 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
804
805 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
806  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
807  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
808  DWORD *pcbFormat)
809 {
810     DWORD size;
811     CERT_BASIC_CONSTRAINTS2_INFO *info;
812     BOOL ret;
813
814     if (!cbEncoded)
815     {
816         SetLastError(E_INVALIDARG);
817         return FALSE;
818     }
819     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
820      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
821     {
822         static const WCHAR pathFmt[] = { '%','d',0 };
823         static BOOL stringsLoaded = FALSE;
824         DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
825         WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
826         LPCWSTR sep, subjectType;
827         DWORD sepLen;
828
829         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
830         {
831             sep = crlf;
832             sepLen = strlenW(crlf) * sizeof(WCHAR);
833         }
834         else
835         {
836             sep = commaSpace;
837             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
838         }
839
840         if (!stringsLoaded)
841         {
842             LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
843              sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
844             LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
845              sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
846             LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
847              subjectTypeEndCert,
848              sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
849             LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
850              sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
851             stringsLoaded = TRUE;
852         }
853         bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
854         if (info->fCA)
855             subjectType = subjectTypeCA;
856         else
857             subjectType = subjectTypeEndCert;
858         bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
859         bytesNeeded += sepLen;
860         bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
861         if (info->fPathLenConstraint)
862             sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
863         else
864             LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
865              sizeof(pathLength) / sizeof(pathLength[0]));
866         bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
867         if (!pbFormat)
868             *pcbFormat = bytesNeeded;
869         else if (*pcbFormat < bytesNeeded)
870         {
871             *pcbFormat = bytesNeeded;
872             SetLastError(ERROR_MORE_DATA);
873             ret = FALSE;
874         }
875         else
876         {
877             LPWSTR str = pbFormat;
878
879             *pcbFormat = bytesNeeded;
880             strcpyW(str, subjectTypeHeader);
881             str += strlenW(subjectTypeHeader);
882             strcpyW(str, subjectType);
883             str += strlenW(subjectType);
884             strcpyW(str, sep);
885             str += sepLen / sizeof(WCHAR);
886             strcpyW(str, pathLengthHeader);
887             str += strlenW(pathLengthHeader);
888             strcpyW(str, pathLength);
889             str += strlenW(pathLength);
890         }
891         LocalFree(info);
892     }
893     return ret;
894 }
895
896 static BOOL CRYPT_FormatHexStringWithPrefix(CRYPT_DATA_BLOB *blob, int id,
897  LPWSTR str, DWORD *pcbStr)
898 {
899     WCHAR buf[MAX_STRING_RESOURCE_LEN];
900     DWORD bytesNeeded;
901     BOOL ret;
902
903     LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
904     CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
905      blob->pbData, blob->cbData, NULL, &bytesNeeded);
906     bytesNeeded += strlenW(buf) * sizeof(WCHAR);
907     if (!str)
908     {
909         *pcbStr = bytesNeeded;
910         ret = TRUE;
911     }
912     else if (*pcbStr < bytesNeeded)
913     {
914         *pcbStr = bytesNeeded;
915         SetLastError(ERROR_MORE_DATA);
916         ret = FALSE;
917     }
918     else
919     {
920         *pcbStr = bytesNeeded;
921         strcpyW(str, buf);
922         str += strlenW(str);
923         bytesNeeded -= strlenW(str) * sizeof(WCHAR);
924         ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
925          blob->pbData, blob->cbData, str, &bytesNeeded);
926     }
927     return ret;
928 }
929
930 static BOOL CRYPT_FormatKeyId(CRYPT_DATA_BLOB *keyId, LPWSTR str,
931  DWORD *pcbStr)
932 {
933     return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
934 }
935
936 static BOOL CRYPT_FormatCertSerialNumber(CRYPT_DATA_BLOB *serialNum, LPWSTR str,
937  DWORD *pcbStr)
938 {
939     return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
940      str, pcbStr);
941 }
942
943 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
944 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
945
946 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
947  CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
948 {
949     BOOL ret;
950     WCHAR buf[MAX_STRING_RESOURCE_LEN];
951     WCHAR mask[MAX_STRING_RESOURCE_LEN];
952     WCHAR ipAddrBuf[32];
953     WCHAR maskBuf[16];
954     DWORD bytesNeeded = sizeof(WCHAR);
955     DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
956
957     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
958         bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
959     switch (entry->dwAltNameChoice)
960     {
961     case CERT_ALT_NAME_RFC822_NAME:
962         LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
963          sizeof(buf) / sizeof(buf[0]));
964         bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
965         ret = TRUE;
966         break;
967     case CERT_ALT_NAME_DNS_NAME:
968         LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
969          sizeof(buf) / sizeof(buf[0]));
970         bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
971         ret = TRUE;
972         break;
973     case CERT_ALT_NAME_DIRECTORY_NAME:
974     {
975         DWORD directoryNameLen;
976
977         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
978             strType |= CERT_NAME_STR_CRLF_FLAG;
979         directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
980          indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
981         LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
982          sizeof(buf) / sizeof(buf[0]));
983         bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
984         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
985             bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
986         else
987             bytesNeeded += sizeof(WCHAR); /* '=' */
988         ret = TRUE;
989         break;
990     }
991     case CERT_ALT_NAME_URL:
992         LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
993          sizeof(buf) / sizeof(buf[0]));
994         bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
995         ret = TRUE;
996         break;
997     case CERT_ALT_NAME_IP_ADDRESS:
998     {
999         static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1000          '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1001         };
1002         static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1003          '.','%','d',0 };
1004
1005         LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1006          sizeof(buf) / sizeof(buf[0]));
1007         if (entry->u.IPAddress.cbData == 8)
1008         {
1009             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1010             {
1011                 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1012                  sizeof(mask) / sizeof(mask[0]));
1013                 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1014                 sprintfW(ipAddrBuf, ipAddrFmt,
1015                  entry->u.IPAddress.pbData[0],
1016                  entry->u.IPAddress.pbData[1],
1017                  entry->u.IPAddress.pbData[2],
1018                  entry->u.IPAddress.pbData[3]);
1019                 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1020                 /* indent again, for the mask line */
1021                 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1022                 sprintfW(maskBuf, ipAddrFmt,
1023                  entry->u.IPAddress.pbData[4],
1024                  entry->u.IPAddress.pbData[5],
1025                  entry->u.IPAddress.pbData[6],
1026                  entry->u.IPAddress.pbData[7]);
1027                 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1028                 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1029             }
1030             else
1031             {
1032                 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1033                  entry->u.IPAddress.pbData[0],
1034                  entry->u.IPAddress.pbData[1],
1035                  entry->u.IPAddress.pbData[2],
1036                  entry->u.IPAddress.pbData[3],
1037                  entry->u.IPAddress.pbData[4],
1038                  entry->u.IPAddress.pbData[5],
1039                  entry->u.IPAddress.pbData[6],
1040                  entry->u.IPAddress.pbData[7]);
1041                 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1042             }
1043             ret = TRUE;
1044         }
1045         else
1046         {
1047             FIXME("unknown IP address format (%d bytes)\n",
1048              entry->u.IPAddress.cbData);
1049             ret = FALSE;
1050         }
1051         break;
1052     }
1053     default:
1054         FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1055         ret = FALSE;
1056     }
1057     if (ret)
1058     {
1059         bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1060         if (!str)
1061             *pcbStr = bytesNeeded;
1062         else if (*pcbStr < bytesNeeded)
1063         {
1064             *pcbStr = bytesNeeded;
1065             SetLastError(ERROR_MORE_DATA);
1066             ret = FALSE;
1067         }
1068         else
1069         {
1070             DWORD i;
1071
1072             *pcbStr = bytesNeeded;
1073             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1074             {
1075                 for (i = 0; i < indentLevel; i++)
1076                 {
1077                     strcpyW(str, indent);
1078                     str += strlenW(indent);
1079                 }
1080             }
1081             strcpyW(str, buf);
1082             str += strlenW(str);
1083             switch (entry->dwAltNameChoice)
1084             {
1085             case CERT_ALT_NAME_RFC822_NAME:
1086             case CERT_ALT_NAME_DNS_NAME:
1087             case CERT_ALT_NAME_URL:
1088                 strcpyW(str, entry->u.pwszURL);
1089                 break;
1090             case CERT_ALT_NAME_DIRECTORY_NAME:
1091                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1092                 {
1093                     strcpyW(str, colonCrlf);
1094                     str += strlenW(colonCrlf);
1095                 }
1096                 else
1097                     *str++ = '=';
1098                 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1099                  indentLevel + 1, &entry->u.DirectoryName, strType, str,
1100                  bytesNeeded / sizeof(WCHAR));
1101                 break;
1102             case CERT_ALT_NAME_IP_ADDRESS:
1103                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1104                 {
1105                     strcpyW(str, ipAddrBuf);
1106                     str += strlenW(ipAddrBuf);
1107                     strcpyW(str, crlf);
1108                     str += strlenW(crlf);
1109                     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1110                     {
1111                         for (i = 0; i < indentLevel; i++)
1112                         {
1113                             strcpyW(str, indent);
1114                             str += strlenW(indent);
1115                         }
1116                     }
1117                     strcpyW(str, mask);
1118                     str += strlenW(mask);
1119                     strcpyW(str, maskBuf);
1120                 }
1121                 else
1122                     strcpyW(str, ipAddrBuf);
1123                 break;
1124             }
1125         }
1126     }
1127     return ret;
1128 }
1129
1130 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1131  CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1132 {
1133     DWORD i, size, bytesNeeded = 0;
1134     BOOL ret = TRUE;
1135     LPCWSTR sep;
1136     DWORD sepLen;
1137
1138     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1139     {
1140         sep = crlf;
1141         sepLen = strlenW(crlf) * sizeof(WCHAR);
1142     }
1143     else
1144     {
1145         sep = commaSpace;
1146         sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1147     }
1148
1149     for (i = 0; ret && i < name->cAltEntry; i++)
1150     {
1151         ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1152          &name->rgAltEntry[i], NULL, &size);
1153         if (ret)
1154         {
1155             bytesNeeded += size - sizeof(WCHAR);
1156             if (i < name->cAltEntry - 1)
1157                 bytesNeeded += sepLen;
1158         }
1159     }
1160     if (ret)
1161     {
1162         bytesNeeded += sizeof(WCHAR);
1163         if (!str)
1164             *pcbStr = bytesNeeded;
1165         else if (*pcbStr < bytesNeeded)
1166         {
1167             *pcbStr = bytesNeeded;
1168             SetLastError(ERROR_MORE_DATA);
1169             ret = FALSE;
1170         }
1171         else
1172         {
1173             *pcbStr = bytesNeeded;
1174             for (i = 0; ret && i < name->cAltEntry; i++)
1175             {
1176                 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1177                  &name->rgAltEntry[i], str, &size);
1178                 if (ret)
1179                 {
1180                     str += size / sizeof(WCHAR) - 1;
1181                     if (i < name->cAltEntry - 1)
1182                     {
1183                         strcpyW(str, sep);
1184                         str += sepLen / sizeof(WCHAR);
1185                     }
1186                 }
1187             }
1188         }
1189     }
1190     return ret;
1191 }
1192
1193 static const WCHAR colonSep[] = { ':',' ',0 };
1194
1195 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1196  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1197  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1198  DWORD *pcbFormat)
1199 {
1200     BOOL ret;
1201     CERT_ALT_NAME_INFO *info;
1202     DWORD size;
1203
1204     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1205      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1206     {
1207         ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1208         LocalFree(info);
1209     }
1210     return ret;
1211 }
1212
1213 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1214  CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1215 {
1216     WCHAR buf[MAX_STRING_RESOURCE_LEN];
1217     DWORD bytesNeeded, sepLen;
1218     LPCWSTR sep;
1219     BOOL ret;
1220
1221     LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1222     ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1223      &bytesNeeded);
1224     bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1225     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1226     {
1227         sep = colonCrlf;
1228         sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1229     }
1230     else
1231     {
1232         sep = colonSep;
1233         sepLen = strlenW(colonSep) * sizeof(WCHAR);
1234     }
1235     bytesNeeded += sepLen;
1236     if (ret)
1237     {
1238         if (!str)
1239             *pcbStr = bytesNeeded;
1240         else if (*pcbStr < bytesNeeded)
1241         {
1242             *pcbStr = bytesNeeded;
1243             SetLastError(ERROR_MORE_DATA);
1244             ret = FALSE;
1245         }
1246         else
1247         {
1248             *pcbStr = bytesNeeded;
1249             strcpyW(str, buf);
1250             bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1251             str += strlenW(str);
1252             strcpyW(str, sep);
1253             str += sepLen / sizeof(WCHAR);
1254             ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1255              &bytesNeeded);
1256         }
1257     }
1258     return ret;
1259 }
1260
1261 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1262  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1263  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1264  DWORD *pcbFormat)
1265 {
1266     CERT_AUTHORITY_KEY_ID2_INFO *info;
1267     DWORD size;
1268     BOOL ret = FALSE;
1269
1270     if (!cbEncoded)
1271     {
1272         SetLastError(E_INVALIDARG);
1273         return FALSE;
1274     }
1275     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1276      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1277     {
1278         DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1279         LPCWSTR sep;
1280         DWORD sepLen;
1281         BOOL needSeparator = FALSE;
1282
1283         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1284         {
1285             sep = crlf;
1286             sepLen = strlenW(crlf) * sizeof(WCHAR);
1287         }
1288         else
1289         {
1290             sep = commaSpace;
1291             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1292         }
1293
1294         if (info->KeyId.cbData)
1295         {
1296             needSeparator = TRUE;
1297             ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1298             if (ret)
1299             {
1300                 /* don't include NULL-terminator more than once */
1301                 bytesNeeded += size - sizeof(WCHAR);
1302             }
1303         }
1304         if (info->AuthorityCertIssuer.cAltEntry)
1305         {
1306             if (needSeparator)
1307                 bytesNeeded += sepLen;
1308             needSeparator = TRUE;
1309             ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1310              &info->AuthorityCertIssuer, NULL, &size);
1311             if (ret)
1312             {
1313                 /* don't include NULL-terminator more than once */
1314                 bytesNeeded += size - sizeof(WCHAR);
1315             }
1316         }
1317         if (info->AuthorityCertSerialNumber.cbData)
1318         {
1319             if (needSeparator)
1320                 bytesNeeded += sepLen;
1321             ret = CRYPT_FormatCertSerialNumber(
1322              &info->AuthorityCertSerialNumber, NULL, &size);
1323             if (ret)
1324             {
1325                 /* don't include NULL-terminator more than once */
1326                 bytesNeeded += size - sizeof(WCHAR);
1327             }
1328         }
1329         if (ret)
1330         {
1331             if (!pbFormat)
1332                 *pcbFormat = bytesNeeded;
1333             else if (*pcbFormat < bytesNeeded)
1334             {
1335                 *pcbFormat = bytesNeeded;
1336                 SetLastError(ERROR_MORE_DATA);
1337                 ret = FALSE;
1338             }
1339             else
1340             {
1341                 LPWSTR str = pbFormat;
1342
1343                 *pcbFormat = bytesNeeded;
1344                 needSeparator = FALSE;
1345                 if (info->KeyId.cbData)
1346                 {
1347                     needSeparator = TRUE;
1348                     /* Overestimate size available, it's already been checked
1349                      * above.
1350                      */
1351                     size = bytesNeeded;
1352                     ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1353                     if (ret)
1354                         str += size / sizeof(WCHAR) - 1;
1355                 }
1356                 if (info->AuthorityCertIssuer.cAltEntry)
1357                 {
1358                     if (needSeparator)
1359                     {
1360                         strcpyW(str, sep);
1361                         str += sepLen / sizeof(WCHAR);
1362                     }
1363                     needSeparator = TRUE;
1364                     /* Overestimate size available, it's already been checked
1365                      * above.
1366                      */
1367                     size = bytesNeeded;
1368                     ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1369                      &info->AuthorityCertIssuer, str, &size);
1370                     if (ret)
1371                         str += size / sizeof(WCHAR) - 1;
1372                 }
1373                 if (info->AuthorityCertSerialNumber.cbData)
1374                 {
1375                     if (needSeparator)
1376                     {
1377                         strcpyW(str, sep);
1378                         str += sepLen / sizeof(WCHAR);
1379                     }
1380                     /* Overestimate size available, it's already been checked
1381                      * above.
1382                      */
1383                     size = bytesNeeded;
1384                     ret = CRYPT_FormatCertSerialNumber(
1385                      &info->AuthorityCertSerialNumber, str, &size);
1386                 }
1387             }
1388         }
1389         LocalFree(info);
1390     }
1391     return ret;
1392 }
1393
1394 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1395 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1396 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1397 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1398 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1399 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1400
1401 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1402  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1403  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1404  DWORD *pcbFormat)
1405 {
1406     CERT_AUTHORITY_INFO_ACCESS *info;
1407     DWORD size;
1408     BOOL ret = FALSE;
1409
1410     if (!cbEncoded)
1411     {
1412         SetLastError(E_INVALIDARG);
1413         return FALSE;
1414     }
1415     if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1416      X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1417      NULL, &info, &size)))
1418     {
1419         DWORD bytesNeeded = sizeof(WCHAR);
1420
1421         if (!info->cAccDescr)
1422         {
1423             WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1424
1425             LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1426              sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1427             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1428             if (!pbFormat)
1429                 *pcbFormat = bytesNeeded;
1430             else if (*pcbFormat < bytesNeeded)
1431             {
1432                 *pcbFormat = bytesNeeded;
1433                 SetLastError(ERROR_MORE_DATA);
1434                 ret = FALSE;
1435             }
1436             else
1437             {
1438                 *pcbFormat = bytesNeeded;
1439                 strcpyW((LPWSTR)pbFormat, infoNotAvailable);
1440             }
1441         }
1442         else
1443         {
1444             static const WCHAR numFmt[] = { '%','d',0 };
1445             static const WCHAR equal[] = { '=',0 };
1446             static BOOL stringsLoaded = FALSE;
1447             DWORD i;
1448             LPCWSTR headingSep, accessMethodSep, locationSep;
1449             WCHAR accessDescrNum[11];
1450
1451             if (!stringsLoaded)
1452             {
1453                 LoadStringW(hInstance, IDS_AIA, aia,
1454                  sizeof(aia) / sizeof(aia[0]));
1455                 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1456                  sizeof(accessMethod) / sizeof(accessMethod[0]));
1457                 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1458                  sizeof(ocsp) / sizeof(ocsp[0]));
1459                 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1460                  sizeof(caIssuers) / sizeof(caIssuers[0]));
1461                 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1462                  sizeof(unknown) / sizeof(unknown[0]));
1463                 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1464                  sizeof(accessLocation) / sizeof(accessLocation[0]));
1465                 stringsLoaded = TRUE;
1466             }
1467             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1468             {
1469                 headingSep = crlf;
1470                 accessMethodSep = crlf;
1471                 locationSep = colonCrlf;
1472             }
1473             else
1474             {
1475                 headingSep = colonSep;
1476                 accessMethodSep = commaSpace;
1477                 locationSep = equal;
1478             }
1479
1480             for (i = 0; ret && i < info->cAccDescr; i++)
1481             {
1482                 /* Heading */
1483                 bytesNeeded += sizeof(WCHAR); /* left bracket */
1484                 sprintfW(accessDescrNum, numFmt, i + 1);
1485                 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1486                 bytesNeeded += sizeof(WCHAR); /* right bracket */
1487                 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1488                 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1489                 /* Access method */
1490                 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1491                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1492                     bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1493                 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1494                  szOID_PKIX_OCSP))
1495                     bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1496                 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1497                  szOID_PKIX_CA_ISSUERS))
1498                     bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1499                 else
1500                     bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1501                 bytesNeeded += sizeof(WCHAR); /* space */
1502                 bytesNeeded += sizeof(WCHAR); /* left paren */
1503                 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1504                  * sizeof(WCHAR);
1505                 bytesNeeded += sizeof(WCHAR); /* right paren */
1506                 /* Delimiter between access method and location */
1507                 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1508                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1509                     bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1510                 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1511                 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1512                 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1513                  &info->rgAccDescr[i].AccessLocation, NULL, &size);
1514                 if (ret)
1515                     bytesNeeded += size - sizeof(WCHAR);
1516                 /* Need extra delimiter between access method entries */
1517                 if (i < info->cAccDescr - 1)
1518                     bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1519             }
1520             if (ret)
1521             {
1522                 if (!pbFormat)
1523                     *pcbFormat = bytesNeeded;
1524                 else if (*pcbFormat < bytesNeeded)
1525                 {
1526                     *pcbFormat = bytesNeeded;
1527                     SetLastError(ERROR_MORE_DATA);
1528                     ret = FALSE;
1529                 }
1530                 else
1531                 {
1532                     LPWSTR str = pbFormat;
1533                     DWORD altNameEntrySize;
1534
1535                     *pcbFormat = bytesNeeded;
1536                     for (i = 0; ret && i < info->cAccDescr; i++)
1537                     {
1538                         LPCSTR oidPtr;
1539
1540                         *str++ = '[';
1541                         sprintfW(accessDescrNum, numFmt, i + 1);
1542                         strcpyW(str, accessDescrNum);
1543                         str += strlenW(accessDescrNum);
1544                         *str++ = ']';
1545                         strcpyW(str, aia);
1546                         str += strlenW(aia);
1547                         strcpyW(str, headingSep);
1548                         str += strlenW(headingSep);
1549                         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1550                         {
1551                             strcpyW(str, indent);
1552                             str += strlenW(indent);
1553                         }
1554                         strcpyW(str, accessMethod);
1555                         str += strlenW(accessMethod);
1556                         if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1557                          szOID_PKIX_OCSP))
1558                         {
1559                             strcpyW(str, ocsp);
1560                             str += strlenW(ocsp);
1561                         }
1562                         else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1563                          szOID_PKIX_CA_ISSUERS))
1564                         {
1565                             strcpyW(str, caIssuers);
1566                             str += strlenW(caIssuers);
1567                         }
1568                         else
1569                         {
1570                             strcpyW(str, unknown);
1571                             str += strlenW(unknown);
1572                         }
1573                         *str++ = ' ';
1574                         *str++ = '(';
1575                         for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1576                          *oidPtr; oidPtr++, str++)
1577                             *str = *oidPtr;
1578                         *str++ = ')';
1579                         strcpyW(str, accessMethodSep);
1580                         str += strlenW(accessMethodSep);
1581                         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1582                         {
1583                             strcpyW(str, indent);
1584                             str += strlenW(indent);
1585                         }
1586                         strcpyW(str, accessLocation);
1587                         str += strlenW(accessLocation);
1588                         strcpyW(str, locationSep);
1589                         str += strlenW(locationSep);
1590                         /* This overestimates the size available, but that
1591                          * won't matter since we checked earlier whether enough
1592                          * space for the entire string was available.
1593                          */
1594                         altNameEntrySize = bytesNeeded;
1595                         ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1596                          &info->rgAccDescr[i].AccessLocation, str,
1597                          &altNameEntrySize);
1598                         if (ret)
1599                             str += altNameEntrySize / sizeof(WCHAR) - 1;
1600                         if (i < info->cAccDescr - 1)
1601                         {
1602                             strcpyW(str, accessMethodSep);
1603                             str += strlenW(accessMethodSep);
1604                         }
1605                     }
1606                 }
1607             }
1608         }
1609         LocalFree(info);
1610     }
1611     return ret;
1612 }
1613
1614 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1615 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1616 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1617 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1618 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1619 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1620
1621 struct reason_map_entry
1622 {
1623     BYTE   reasonBit;
1624     LPWSTR reason;
1625     int    id;
1626 };
1627 static struct reason_map_entry reason_map[] = {
1628  { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1629  { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1630  { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1631    IDS_REASON_AFFILIATION_CHANGED },
1632  { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1633  { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1634    IDS_REASON_CESSATION_OF_OPERATION },
1635  { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1636    IDS_REASON_CERTIFICATE_HOLD },
1637 };
1638
1639 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1640  const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1641 {
1642     static const WCHAR sep[] = { ',',' ',0 };
1643     static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1644     static BOOL stringsLoaded = FALSE;
1645     int i, numReasons = 0;
1646     BOOL ret = TRUE;
1647     DWORD bytesNeeded = sizeof(WCHAR);
1648     WCHAR bits[6];
1649
1650     if (!stringsLoaded)
1651     {
1652         for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1653             LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1654              MAX_STRING_RESOURCE_LEN);
1655         stringsLoaded = TRUE;
1656     }
1657     /* No need to check reasonFlags->cbData, we already know it's positive.
1658      * Ignore any other bytes, as they're for undefined bits.
1659      */
1660     for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1661     {
1662         if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1663         {
1664             bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1665             if (numReasons++)
1666                 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1667         }
1668     }
1669     sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1670     bytesNeeded += strlenW(bits);
1671     if (!str)
1672         *pcbStr = bytesNeeded;
1673     else if (*pcbStr < bytesNeeded)
1674     {
1675         *pcbStr = bytesNeeded;
1676         SetLastError(ERROR_MORE_DATA);
1677         ret = FALSE;
1678     }
1679     else
1680     {
1681         *pcbStr = bytesNeeded;
1682         for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1683         {
1684             if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1685             {
1686                 strcpyW(str, reason_map[i].reason);
1687                 str += strlenW(reason_map[i].reason);
1688                 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1689                  numReasons)
1690                 {
1691                     strcpyW(str, sep);
1692                     str += strlenW(sep);
1693                 }
1694             }
1695         }
1696         strcpyW(str, bits);
1697     }
1698     return ret;
1699 }
1700
1701 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1702 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1703 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1704 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1705 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1706 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1707
1708 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1709  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1710  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1711  DWORD *pcbFormat)
1712 {
1713     CRL_DIST_POINTS_INFO *info;
1714     DWORD size;
1715     BOOL ret = FALSE;
1716
1717     if (!cbEncoded)
1718     {
1719         SetLastError(E_INVALIDARG);
1720         return FALSE;
1721     }
1722     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1723      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1724     {
1725         static const WCHAR numFmt[] = { '%','d',0 };
1726         static const WCHAR commaSep[] = { ',',' ',0 };
1727         static const WCHAR colon[] = { ':',0 };
1728         static BOOL stringsLoaded = FALSE;
1729         DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1730         BOOL haveAnEntry = FALSE;
1731         LPCWSTR headingSep, distPointSep, nameSep;
1732         WCHAR distPointNum[11];
1733         DWORD i;
1734
1735         if (!stringsLoaded)
1736         {
1737             LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1738              sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1739             LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1740              sizeof(distPointName) / sizeof(distPointName[0]));
1741             LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1742              sizeof(fullName) / sizeof(fullName[0]));
1743             LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1744              sizeof(rdnName) / sizeof(rdnName[0]));
1745             LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1746              sizeof(reason) / sizeof(reason[0]));
1747             LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1748              sizeof(issuer) / sizeof(issuer[0]));
1749             stringsLoaded = TRUE;
1750         }
1751         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1752         {
1753             headingSep = crlf;
1754             distPointSep = crlf;
1755             nameSep = colonCrlf;
1756         }
1757         else
1758         {
1759             headingSep = colonSep;
1760             distPointSep = commaSep;
1761             nameSep = colon;
1762         }
1763
1764         for (i = 0; ret && i < info->cDistPoint; i++)
1765         {
1766             CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1767
1768             if (distPoint->DistPointName.dwDistPointNameChoice !=
1769              CRL_DIST_POINT_NO_NAME)
1770             {
1771                 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1772                 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1773                 if (distPoint->DistPointName.dwDistPointNameChoice ==
1774                  CRL_DIST_POINT_FULL_NAME)
1775                     bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
1776                 else
1777                     bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
1778                 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1779                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1780                     bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
1781                 /* The indent level (3) is higher than when used as the issuer,
1782                  * because the name is subordinate to the name type (full vs.
1783                  * RDN.)
1784                  */
1785                 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
1786                  &distPoint->DistPointName.u.FullName, NULL, &size);
1787                 if (ret)
1788                     bytesNeeded += size - sizeof(WCHAR);
1789                 haveAnEntry = TRUE;
1790             }
1791             else if (distPoint->ReasonFlags.cbData)
1792             {
1793                 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
1794                 ret = CRYPT_FormatReason(dwFormatStrType,
1795                  &distPoint->ReasonFlags, NULL, &size);
1796                 if (ret)
1797                     bytesNeeded += size - sizeof(WCHAR);
1798                 haveAnEntry = TRUE;
1799             }
1800             else if (distPoint->CRLIssuer.cAltEntry)
1801             {
1802                 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
1803                 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1804                 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
1805                  &distPoint->CRLIssuer, NULL, &size);
1806                 if (ret)
1807                     bytesNeeded += size - sizeof(WCHAR);
1808                 haveAnEntry = TRUE;
1809             }
1810             if (haveAnEntry)
1811             {
1812                 bytesNeeded += sizeof(WCHAR); /* left bracket */
1813                 sprintfW(distPointNum, numFmt, i + 1);
1814                 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
1815                 bytesNeeded += sizeof(WCHAR); /* right bracket */
1816                 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
1817                 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1818                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1819                     bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1820             }
1821         }
1822         if (!haveAnEntry)
1823         {
1824             WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1825
1826             LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1827              sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1828             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1829             if (!pbFormat)
1830                 *pcbFormat = bytesNeeded;
1831             else if (*pcbFormat < bytesNeeded)
1832             {
1833                 *pcbFormat = bytesNeeded;
1834                 SetLastError(ERROR_MORE_DATA);
1835                 ret = FALSE;
1836             }
1837             else
1838             {
1839                 *pcbFormat = bytesNeeded;
1840                 strcpyW((LPWSTR)pbFormat, infoNotAvailable);
1841             }
1842         }
1843         else
1844         {
1845             if (!pbFormat)
1846                 *pcbFormat = bytesNeeded;
1847             else if (*pcbFormat < bytesNeeded)
1848             {
1849                 *pcbFormat = bytesNeeded;
1850                 SetLastError(ERROR_MORE_DATA);
1851                 ret = FALSE;
1852             }
1853             else
1854             {
1855                 LPWSTR str = pbFormat;
1856
1857                 *pcbFormat = bytesNeeded;
1858                 for (i = 0; ret && i < info->cDistPoint; i++)
1859                 {
1860                     CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1861
1862                     *str++ = '[';
1863                     sprintfW(distPointNum, numFmt, i + 1);
1864                     strcpyW(str, distPointNum);
1865                     str += strlenW(distPointNum);
1866                     *str++ = ']';
1867                     strcpyW(str, crlDistPoint);
1868                     str += strlenW(crlDistPoint);
1869                     strcpyW(str, headingSep);
1870                     str += strlenW(headingSep);
1871                     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1872                     {
1873                         strcpyW(str, indent);
1874                         str += strlenW(indent);
1875                     }
1876                     if (distPoint->DistPointName.dwDistPointNameChoice !=
1877                      CRL_DIST_POINT_NO_NAME)
1878                     {
1879                         DWORD altNameSize = bytesNeeded;
1880
1881                         strcpyW(str, distPointName);
1882                         str += strlenW(distPointName);
1883                         strcpyW(str, nameSep);
1884                         str += strlenW(nameSep);
1885                         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1886                         {
1887                             strcpyW(str, indent);
1888                             str += strlenW(indent);
1889                             strcpyW(str, indent);
1890                             str += strlenW(indent);
1891                         }
1892                         if (distPoint->DistPointName.dwDistPointNameChoice ==
1893                          CRL_DIST_POINT_FULL_NAME)
1894                         {
1895                             strcpyW(str, fullName);
1896                             str += strlenW(fullName);
1897                         }
1898                         else
1899                         {
1900                             strcpyW(str, rdnName);
1901                             str += strlenW(rdnName);
1902                         }
1903                         strcpyW(str, nameSep);
1904                         str += strlenW(nameSep);
1905                         ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
1906                          &distPoint->DistPointName.u.FullName, str,
1907                          &altNameSize);
1908                         if (ret)
1909                             str += altNameSize / sizeof(WCHAR) - 1;
1910                     }
1911                     else if (distPoint->ReasonFlags.cbData)
1912                     {
1913                         DWORD reasonSize = bytesNeeded;
1914
1915                         strcpyW(str, reason);
1916                         str += strlenW(reason);
1917                         ret = CRYPT_FormatReason(dwFormatStrType,
1918                          &distPoint->ReasonFlags, str, &reasonSize);
1919                         if (ret)
1920                             str += reasonSize / sizeof(WCHAR) - 1;
1921                     }
1922                     else if (distPoint->CRLIssuer.cAltEntry)
1923                     {
1924                         DWORD crlIssuerSize = bytesNeeded;
1925
1926                         strcpyW(str, issuer);
1927                         str += strlenW(issuer);
1928                         strcpyW(str, nameSep);
1929                         str += strlenW(nameSep);
1930                         ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
1931                          &distPoint->CRLIssuer, str,
1932                          &crlIssuerSize);
1933                         if (ret)
1934                             str += crlIssuerSize / sizeof(WCHAR) - 1;
1935                     }
1936                 }
1937             }
1938         }
1939         LocalFree(info);
1940     }
1941     return ret;
1942 }
1943
1944 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
1945  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1946  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1947  DWORD *pcbFormat)
1948 {
1949     CERT_ENHKEY_USAGE *usage;
1950     DWORD size;
1951     BOOL ret = FALSE;
1952
1953     if (!cbEncoded)
1954     {
1955         SetLastError(E_INVALIDARG);
1956         return FALSE;
1957     }
1958     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
1959      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
1960     {
1961         WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1962         DWORD i;
1963         DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1964         LPCWSTR sep;
1965         DWORD sepLen;
1966
1967         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1968         {
1969             sep = crlf;
1970             sepLen = strlenW(crlf) * sizeof(WCHAR);
1971         }
1972         else
1973         {
1974             sep = commaSpace;
1975             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1976         }
1977
1978         LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
1979          sizeof(unknown) / sizeof(unknown[0]));
1980         for (i = 0; i < usage->cUsageIdentifier; i++)
1981         {
1982             PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1983              usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1984
1985             if (info)
1986                 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
1987             else
1988                 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1989             bytesNeeded += sizeof(WCHAR); /* space */
1990             bytesNeeded += sizeof(WCHAR); /* left paren */
1991             bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
1992              sizeof(WCHAR);
1993             bytesNeeded += sizeof(WCHAR); /* right paren */
1994             if (i < usage->cUsageIdentifier - 1)
1995                 bytesNeeded += sepLen;
1996         }
1997         if (!pbFormat)
1998             *pcbFormat = bytesNeeded;
1999         else if (*pcbFormat < bytesNeeded)
2000         {
2001             *pcbFormat = bytesNeeded;
2002             SetLastError(ERROR_MORE_DATA);
2003             ret = FALSE;
2004         }
2005         else
2006         {
2007             LPWSTR str = pbFormat;
2008
2009             *pcbFormat = bytesNeeded;
2010             for (i = 0; i < usage->cUsageIdentifier; i++)
2011             {
2012                 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2013                  usage->rgpszUsageIdentifier[i],
2014                  CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2015                 LPCSTR oidPtr;
2016
2017                 if (info)
2018                 {
2019                     strcpyW(str, info->pwszName);
2020                     str += strlenW(info->pwszName);
2021                 }
2022                 else
2023                 {
2024                     strcpyW(str, unknown);
2025                     str += strlenW(unknown);
2026                 }
2027                 *str++ = ' ';
2028                 *str++ = '(';
2029                 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2030                     *str++ = *oidPtr;
2031                 *str++ = ')';
2032                 *str = 0;
2033                 if (i < usage->cUsageIdentifier - 1)
2034                 {
2035                     strcpyW(str, sep);
2036                     str += sepLen / sizeof(WCHAR);
2037                 }
2038             }
2039         }
2040         LocalFree(usage);
2041     }
2042     return ret;
2043 }
2044
2045 static struct BitToString netscapeCertTypeMap[] = {
2046  { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2047  { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2048  { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2049  { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2050  { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2051  { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2052  { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2053 };
2054
2055 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2056  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2057  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2058  DWORD *pcbFormat)
2059 {
2060     DWORD size;
2061     CRYPT_BIT_BLOB *bits;
2062     BOOL ret;
2063
2064     if (!cbEncoded)
2065     {
2066         SetLastError(E_INVALIDARG);
2067         return FALSE;
2068     }
2069     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2070      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2071     {
2072         WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2073         DWORD bytesNeeded = sizeof(WCHAR);
2074
2075         LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2076          sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2077         if (!bits->cbData || bits->cbData > 1)
2078         {
2079             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2080             if (!pbFormat)
2081                 *pcbFormat = bytesNeeded;
2082             else if (*pcbFormat < bytesNeeded)
2083             {
2084                 *pcbFormat = bytesNeeded;
2085                 SetLastError(ERROR_MORE_DATA);
2086                 ret = FALSE;
2087             }
2088             else
2089             {
2090                 LPWSTR str = pbFormat;
2091
2092                 *pcbFormat = bytesNeeded;
2093                 strcpyW(str, infoNotAvailable);
2094             }
2095         }
2096         else
2097         {
2098             static BOOL stringsLoaded = FALSE;
2099             int i;
2100             DWORD bitStringLen;
2101             BOOL first = TRUE;
2102
2103             if (!stringsLoaded)
2104             {
2105                 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2106                  sizeof(netscapeCertTypeMap[0]); i++)
2107                     LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2108                      netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2109                 stringsLoaded = TRUE;
2110             }
2111             CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2112              sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2113              NULL, &bitStringLen, &first);
2114             bytesNeeded += bitStringLen;
2115             bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2116             CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2117              bits->cbData, NULL, &size);
2118             bytesNeeded += size;
2119             if (!pbFormat)
2120                 *pcbFormat = bytesNeeded;
2121             else if (*pcbFormat < bytesNeeded)
2122             {
2123                 *pcbFormat = bytesNeeded;
2124                 SetLastError(ERROR_MORE_DATA);
2125                 ret = FALSE;
2126             }
2127             else
2128             {
2129                 LPWSTR str = pbFormat;
2130
2131                 bitStringLen = bytesNeeded;
2132                 first = TRUE;
2133                 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2134                  sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2135                  str, &bitStringLen, &first);
2136                 str += bitStringLen / sizeof(WCHAR) - 1;
2137                 *str++ = ' ';
2138                 *str++ = '(';
2139                 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2140                  bits->cbData, str, &size);
2141                 str += size / sizeof(WCHAR) - 1;
2142                 *str++ = ')';
2143                 *str = 0;
2144             }
2145         }
2146         LocalFree(bits);
2147     }
2148     return ret;
2149 }
2150
2151 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2152 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2153 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2154 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2155 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2156 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2157
2158 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2159  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2160  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2161  DWORD *pcbFormat)
2162 {
2163     SPC_FINANCIAL_CRITERIA criteria;
2164     DWORD size = sizeof(criteria);
2165     BOOL ret = FALSE;
2166
2167     if (!cbEncoded)
2168     {
2169         SetLastError(E_INVALIDARG);
2170         return FALSE;
2171     }
2172     if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2173      SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2174      &size)))
2175     {
2176         static BOOL stringsLoaded = FALSE;
2177         DWORD bytesNeeded = sizeof(WCHAR);
2178         LPCWSTR sep;
2179         DWORD sepLen;
2180
2181         if (!stringsLoaded)
2182         {
2183             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2184              sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2185             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2186              sizeof(available) / sizeof(available[0]));
2187             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2188              notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2189             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2190              meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2191             LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2192             LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2193             stringsLoaded = TRUE;
2194         }
2195         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2196         {
2197             sep = crlf;
2198             sepLen = strlenW(crlf) * sizeof(WCHAR);
2199         }
2200         else
2201         {
2202             sep = commaSpace;
2203             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2204         }
2205         bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2206         if (criteria.fFinancialInfoAvailable)
2207         {
2208             bytesNeeded += strlenW(available) * sizeof(WCHAR);
2209             bytesNeeded += sepLen;
2210             bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2211             if (criteria.fMeetsCriteria)
2212                 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2213             else
2214                 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2215         }
2216         else
2217             bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2218         if (!pbFormat)
2219             *pcbFormat = bytesNeeded;
2220         else if (*pcbFormat < bytesNeeded)
2221         {
2222             *pcbFormat = bytesNeeded;
2223             SetLastError(ERROR_MORE_DATA);
2224             ret = FALSE;
2225         }
2226         else
2227         {
2228             LPWSTR str = pbFormat;
2229
2230             *pcbFormat = bytesNeeded;
2231             strcpyW(str, financialCriteria);
2232             str += strlenW(financialCriteria);
2233             if (criteria.fFinancialInfoAvailable)
2234             {
2235                 strcpyW(str, available);
2236                 str += strlenW(available);
2237                 strcpyW(str, sep);
2238                 str += sepLen / sizeof(WCHAR);
2239                 strcpyW(str, meetsCriteria);
2240                 str += strlenW(meetsCriteria);
2241                 if (criteria.fMeetsCriteria)
2242                     strcpyW(str, yes);
2243                 else
2244                     strcpyW(str, no);
2245             }
2246             else
2247             {
2248                 strcpyW(str, notAvailable);
2249                 str += strlenW(notAvailable);
2250             }
2251         }
2252     }
2253     return ret;
2254 }
2255
2256 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2257  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2258  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2259  DWORD *pcbFormat)
2260 {
2261     CERT_NAME_VALUE *value;
2262     DWORD size;
2263     BOOL ret;
2264
2265     if (!cbEncoded)
2266     {
2267         SetLastError(E_INVALIDARG);
2268         return FALSE;
2269     }
2270     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2271      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2272     {
2273         if (!pbFormat)
2274             *pcbFormat = value->Value.cbData;
2275         else if (*pcbFormat < value->Value.cbData)
2276         {
2277             *pcbFormat = value->Value.cbData;
2278             SetLastError(ERROR_MORE_DATA);
2279             ret = FALSE;
2280         }
2281         else
2282         {
2283             LPWSTR str = pbFormat;
2284
2285             *pcbFormat = value->Value.cbData;
2286             strcpyW(str, (LPWSTR)value->Value.pbData);
2287         }
2288     }
2289     return ret;
2290 }
2291
2292 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2293  LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2294
2295 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2296  DWORD formatStrType, LPCSTR lpszStructType)
2297 {
2298     CryptFormatObjectFunc format = NULL;
2299
2300     if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2301     {
2302         SetLastError(ERROR_FILE_NOT_FOUND);
2303         return NULL;
2304     }
2305     if (!HIWORD(lpszStructType))
2306     {
2307         switch (LOWORD(lpszStructType))
2308         {
2309         case LOWORD(X509_KEY_USAGE):
2310             format = CRYPT_FormatKeyUsage;
2311             break;
2312         case LOWORD(X509_ALTERNATE_NAME):
2313             format = CRYPT_FormatAltName;
2314             break;
2315         case LOWORD(X509_BASIC_CONSTRAINTS2):
2316             format = CRYPT_FormatBasicConstraints2;
2317             break;
2318         case LOWORD(X509_AUTHORITY_KEY_ID2):
2319             format = CRYPT_FormatAuthorityKeyId2;
2320             break;
2321         case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2322             format = CRYPT_FormatAuthorityInfoAccess;
2323             break;
2324         case LOWORD(X509_CRL_DIST_POINTS):
2325             format = CRYPT_FormatCRLDistPoints;
2326             break;
2327         case LOWORD(X509_ENHANCED_KEY_USAGE):
2328             format = CRYPT_FormatEnhancedKeyUsage;
2329             break;
2330         case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2331             format = CRYPT_FormatSpcFinancialCriteria;
2332             break;
2333         }
2334     }
2335     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2336         format = CRYPT_FormatAltName;
2337     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2338         format = CRYPT_FormatAltName;
2339     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2340         format = CRYPT_FormatKeyUsage;
2341     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2342         format = CRYPT_FormatAltName;
2343     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2344         format = CRYPT_FormatAltName;
2345     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2346         format = CRYPT_FormatBasicConstraints2;
2347     else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2348         format = CRYPT_FormatAuthorityInfoAccess;
2349     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2350         format = CRYPT_FormatAuthorityKeyId2;
2351     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2352         format = CRYPT_FormatCRLDistPoints;
2353     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2354         format = CRYPT_FormatEnhancedKeyUsage;
2355     else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2356         format = CRYPT_FormatNetscapeCertType;
2357     else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2358      !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2359      !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2360      !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2361      !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2362      !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2363      !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2364         format = CRYPT_FormatUnicodeString;
2365     else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2366         format = CRYPT_FormatSpcFinancialCriteria;
2367     return format;
2368 }
2369
2370 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2371  DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2372  const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2373 {
2374     CryptFormatObjectFunc format = NULL;
2375     HCRYPTOIDFUNCADDR hFunc = NULL;
2376     BOOL ret = FALSE;
2377
2378     TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2379      dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2380      pbEncoded, cbEncoded, pbFormat, pcbFormat);
2381
2382     if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2383      dwFormatStrType, lpszStructType)))
2384     {
2385         static HCRYPTOIDFUNCSET set = NULL;
2386
2387         if (!set)
2388             set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2389         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2390          (void **)&format, &hFunc);
2391     }
2392     if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2393      X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2394         format = CRYPT_FormatHexString;
2395     if (format)
2396         ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2397          pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2398          pcbFormat);
2399     if (hFunc)
2400         CryptFreeOIDFunctionAddress(hFunc, 0);
2401     return ret;
2402 }