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