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