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