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