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