push 07a2b33f792746135ccf34a3b3e1dfb2a3c1e823
[wine/hacks.git] / dlls / crypt32 / object.c
blob5784cc96f6847769375a7dbf9469ebd5d46ec487
1 /*
2 * crypt32 Crypt*Object functions
4 * Copyright 2007 Juan Lang
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.
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.
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
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"
33 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
35 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
37 BOOL ret = FALSE;
38 HANDLE file;
40 TRACE("%s\n", debugstr_w(fileName));
42 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
43 OPEN_EXISTING, 0, NULL);
44 if (file != INVALID_HANDLE_VALUE)
46 ret = TRUE;
47 blob->cbData = GetFileSize(file, NULL);
48 if (blob->cbData)
50 blob->pbData = CryptMemAlloc(blob->cbData);
51 if (blob->pbData)
53 DWORD read;
55 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
58 CloseHandle(file);
60 TRACE("returning %d\n", ret);
61 return ret;
64 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
65 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
66 DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
68 CERT_BLOB fileBlob;
69 const CERT_BLOB *blob;
70 HCERTSTORE store;
71 DWORD contentType;
72 BOOL ret;
74 switch (dwObjectType)
76 case CERT_QUERY_OBJECT_FILE:
77 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
78 * just read the file directly
80 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
81 blob = &fileBlob;
82 break;
83 case CERT_QUERY_OBJECT_BLOB:
84 blob = (const CERT_BLOB *)pvObject;
85 ret = TRUE;
86 break;
87 default:
88 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
89 ret = FALSE;
91 if (!ret)
92 return FALSE;
94 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
95 CERT_STORE_CREATE_NEW_FLAG, NULL);
96 ret = FALSE;
97 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
99 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
100 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
101 if (ret)
102 contentType = CERT_QUERY_CONTENT_CERT;
104 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
106 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
107 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
108 if (ret)
109 contentType = CERT_QUERY_CONTENT_CRL;
111 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
113 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
114 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
115 if (ret)
116 contentType = CERT_QUERY_CONTENT_CTL;
118 if (ret)
120 if (pdwMsgAndCertEncodingType)
121 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
122 if (pdwContentType)
123 *pdwContentType = contentType;
124 if (phCertStore)
125 *phCertStore = CertDuplicateStore(store);
127 CertCloseStore(store, 0);
128 if (blob == &fileBlob)
129 CryptMemFree(blob->pbData);
130 TRACE("returning %d\n", ret);
131 return ret;
134 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
135 const void *pvObject, DWORD dwExpectedContentTypeFlags,
136 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
137 HCERTSTORE *phCertStore, const void **ppvContext)
139 CERT_BLOB fileBlob;
140 const CERT_BLOB *blob;
141 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
142 const void *context;
143 DWORD contextType;
144 BOOL ret;
146 switch (dwObjectType)
148 case CERT_QUERY_OBJECT_FILE:
149 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
150 * just read the file directly
152 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
153 blob = &fileBlob;
154 break;
155 case CERT_QUERY_OBJECT_BLOB:
156 blob = (const CERT_BLOB *)pvObject;
157 ret = TRUE;
158 break;
159 default:
160 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
161 ret = FALSE;
163 if (!ret)
164 return FALSE;
166 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
167 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
168 if (context)
170 DWORD contentType, certStoreOffset;
172 ret = TRUE;
173 switch (contextType)
175 case CERT_STORE_CERTIFICATE_CONTEXT:
176 contextInterface = pCertInterface;
177 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
178 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
179 if (!(dwExpectedContentTypeFlags &
180 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
182 SetLastError(ERROR_INVALID_DATA);
183 ret = FALSE;
184 goto end;
186 break;
187 case CERT_STORE_CRL_CONTEXT:
188 contextInterface = pCRLInterface;
189 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
190 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
191 if (!(dwExpectedContentTypeFlags &
192 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
194 SetLastError(ERROR_INVALID_DATA);
195 ret = FALSE;
196 goto end;
198 break;
199 case CERT_STORE_CTL_CONTEXT:
200 contextInterface = pCTLInterface;
201 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
202 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
203 if (!(dwExpectedContentTypeFlags &
204 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
206 SetLastError(ERROR_INVALID_DATA);
207 ret = FALSE;
208 goto end;
210 break;
211 default:
212 SetLastError(ERROR_INVALID_DATA);
213 ret = FALSE;
214 goto end;
216 if (pdwMsgAndCertEncodingType)
217 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
218 if (pdwContentType)
219 *pdwContentType = contentType;
220 if (phCertStore)
221 *phCertStore = CertDuplicateStore(
222 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
223 if (ppvContext)
224 *ppvContext = contextInterface->duplicate(context);
227 end:
228 if (contextInterface && context)
229 contextInterface->free(context);
230 if (blob == &fileBlob)
231 CryptMemFree(blob->pbData);
232 TRACE("returning %d\n", ret);
233 return ret;
236 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
237 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
238 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
240 LPCWSTR fileName = (LPCWSTR)pvObject;
241 HANDLE file;
242 BOOL ret = FALSE;
244 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
246 FIXME("unimplemented for non-file type %d\n", dwObjectType);
247 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
248 return FALSE;
250 TRACE("%s\n", debugstr_w(fileName));
251 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
252 OPEN_EXISTING, 0, NULL);
253 if (file != INVALID_HANDLE_VALUE)
255 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
256 CERT_STORE_CREATE_NEW_FLAG, NULL);
258 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
259 if (ret)
261 if (pdwMsgAndCertEncodingType)
262 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
263 if (pdwContentType)
264 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
265 if (phCertStore)
266 *phCertStore = CertDuplicateStore(store);
268 CertCloseStore(store, 0);
269 CloseHandle(file);
271 TRACE("returning %d\n", ret);
272 return ret;
275 /* Used to decode non-embedded messages */
276 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
277 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
278 DWORD *pdwContentType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
280 CERT_BLOB fileBlob;
281 const CERT_BLOB *blob;
282 BOOL ret;
283 HCRYPTMSG msg = NULL;
284 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
286 switch (dwObjectType)
288 case CERT_QUERY_OBJECT_FILE:
289 /* This isn't an embedded PKCS7 message, so just read the file
290 * directly
292 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
293 blob = &fileBlob;
294 break;
295 case CERT_QUERY_OBJECT_BLOB:
296 blob = (const CERT_BLOB *)pvObject;
297 ret = TRUE;
298 break;
299 default:
300 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
301 ret = FALSE;
303 if (!ret)
304 return FALSE;
306 ret = FALSE;
307 /* Try it first as a PKCS content info */
308 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
309 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
311 msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL);
312 if (msg)
314 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
315 if (ret)
317 DWORD type, len = sizeof(type);
319 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
320 if (ret)
322 if ((dwExpectedContentTypeFlags &
323 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
325 if (type != CMSG_SIGNED)
327 SetLastError(ERROR_INVALID_DATA);
328 ret = FALSE;
330 else if (pdwContentType)
331 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
333 else if ((dwExpectedContentTypeFlags &
334 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
336 if (type != CMSG_DATA)
338 SetLastError(ERROR_INVALID_DATA);
339 ret = FALSE;
341 else if (pdwContentType)
342 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
346 if (!ret)
348 CryptMsgClose(msg);
349 msg = NULL;
353 /* Failing that, try explicitly typed messages */
354 if (!ret &&
355 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
357 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
358 if (msg)
360 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
361 if (!ret)
363 CryptMsgClose(msg);
364 msg = NULL;
367 if (msg && pdwContentType)
368 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
370 if (!ret &&
371 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
373 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
374 if (msg)
376 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
377 if (!ret)
379 CryptMsgClose(msg);
380 msg = NULL;
383 if (msg && pdwContentType)
384 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
386 if (pdwMsgAndCertEncodingType)
387 *pdwMsgAndCertEncodingType = encodingType;
388 if (msg)
390 if (phMsg)
391 *phMsg = msg;
392 if (phCertStore)
393 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
394 0, msg);
396 if (blob == &fileBlob)
397 CryptMemFree(blob->pbData);
398 TRACE("returning %d\n", ret);
399 return ret;
402 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
403 const void *pvObject, DWORD dwExpectedContentTypeFlags,
404 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
405 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
407 HANDLE file;
408 GUID subject;
409 BOOL ret = FALSE;
411 TRACE("%s\n", debugstr_w((LPCWSTR)pvObject));
413 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
415 FIXME("don't know what to do for type %d embedded signed messages\n",
416 dwObjectType);
417 SetLastError(E_INVALIDARG);
418 return FALSE;
420 file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ,
421 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
422 if (file != INVALID_HANDLE_VALUE)
424 ret = CryptSIPRetrieveSubjectGuid((LPCWSTR)pvObject, file, &subject);
425 if (ret)
427 SIP_DISPATCH_INFO sip;
429 memset(&sip, 0, sizeof(sip));
430 sip.cbSize = sizeof(sip);
431 ret = CryptSIPLoad(&subject, 0, &sip);
432 if (ret)
434 SIP_SUBJECTINFO subjectInfo;
435 CERT_BLOB blob;
436 DWORD encodingType;
438 memset(&subjectInfo, 0, sizeof(subjectInfo));
439 subjectInfo.cbSize = sizeof(subjectInfo);
440 subjectInfo.pgSubjectType = &subject;
441 subjectInfo.hFile = file;
442 subjectInfo.pwsFileName = (LPCWSTR)pvObject;
443 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
444 NULL);
445 if (ret)
447 blob.pbData = CryptMemAlloc(blob.cbData);
448 if (blob.pbData)
450 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
451 &blob.cbData, blob.pbData);
452 if (ret)
454 ret = CRYPT_QueryMessageObject(
455 CERT_QUERY_OBJECT_BLOB, &blob,
456 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
457 pdwMsgAndCertEncodingType, NULL, phCertStore,
458 phMsg);
459 if (ret && pdwContentType)
460 *pdwContentType =
461 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
463 CryptMemFree(blob.pbData);
465 else
467 SetLastError(ERROR_OUTOFMEMORY);
468 ret = FALSE;
473 CloseHandle(file);
475 TRACE("returning %d\n", ret);
476 return ret;
479 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
480 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
481 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
482 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
483 const void **ppvContext)
485 static const DWORD unimplementedTypes =
486 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
487 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
488 BOOL ret = TRUE;
490 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
491 dwObjectType, pvObject, dwExpectedContentTypeFlags,
492 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
493 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
495 if (dwExpectedContentTypeFlags & unimplementedTypes)
496 WARN("unimplemented for types %08x\n",
497 dwExpectedContentTypeFlags & unimplementedTypes);
498 if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY))
500 FIXME("unimplemented for anything but binary\n");
501 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
502 return FALSE;
504 if (pdwFormatType)
505 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
507 if (phCertStore)
508 *phCertStore = NULL;
509 if (phMsg)
510 *phMsg = NULL;
511 if (ppvContext)
512 *ppvContext = NULL;
514 ret = FALSE;
515 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
516 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
517 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
519 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
520 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
521 phCertStore, ppvContext);
523 if (!ret &&
524 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
526 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
527 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
529 if (!ret &&
530 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
531 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
532 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
534 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
535 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
536 phCertStore, ppvContext);
538 if (!ret &&
539 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
540 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
542 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
543 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
544 phCertStore, phMsg);
546 if (!ret &&
547 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
549 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
550 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
551 phCertStore, phMsg);
553 TRACE("returning %d\n", ret);
554 return ret;
557 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
558 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
559 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
560 DWORD *pcbFormat)
562 BOOL ret;
563 DWORD bytesNeeded;
565 if (cbEncoded)
566 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
567 else
568 bytesNeeded = sizeof(WCHAR);
569 if (!pbFormat)
571 *pcbFormat = bytesNeeded;
572 ret = TRUE;
574 else if (*pcbFormat < bytesNeeded)
576 *pcbFormat = bytesNeeded;
577 SetLastError(ERROR_MORE_DATA);
578 ret = FALSE;
580 else
582 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
583 static const WCHAR endFmt[] = { '%','0','2','x',0 };
584 DWORD i;
585 LPWSTR ptr = pbFormat;
587 *pcbFormat = bytesNeeded;
588 if (cbEncoded)
590 for (i = 0; i < cbEncoded; i++)
592 if (i < cbEncoded - 1)
593 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
594 else
595 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
598 else
599 *ptr = 0;
600 ret = TRUE;
602 return ret;
605 #define MAX_STRING_RESOURCE_LEN 128
607 static const WCHAR commaSpace[] = { ',',' ',0 };
609 struct BitToString
611 BYTE bit;
612 int id;
613 WCHAR str[MAX_STRING_RESOURCE_LEN];
616 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
617 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
619 DWORD bytesNeeded = sizeof(WCHAR);
620 int i;
621 BOOL ret = TRUE, localFirst = *first;
623 for (i = 0; i < mapEntries; i++)
624 if (bits & map[i].bit)
626 if (!localFirst)
627 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
628 localFirst = FALSE;
629 bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
631 if (!pbFormat)
633 *first = localFirst;
634 *pcbFormat = bytesNeeded;
636 else if (*pcbFormat < bytesNeeded)
638 *first = localFirst;
639 *pcbFormat = bytesNeeded;
640 SetLastError(ERROR_MORE_DATA);
641 ret = FALSE;
643 else
645 LPWSTR str = pbFormat;
647 localFirst = *first;
648 *pcbFormat = bytesNeeded;
649 for (i = 0; i < mapEntries; i++)
650 if (bits & map[i].bit)
652 if (!localFirst)
654 strcpyW(str, commaSpace);
655 str += strlenW(commaSpace);
657 localFirst = FALSE;
658 strcpyW(str, map[i].str);
659 str += strlenW(map[i].str);
661 *first = localFirst;
663 return ret;
666 static struct BitToString keyUsageByte0Map[] = {
667 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
668 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
669 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
670 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
671 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
672 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
673 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
674 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
675 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
677 static struct BitToString keyUsageByte1Map[] = {
678 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
681 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
682 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
683 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
684 DWORD *pcbFormat)
686 DWORD size;
687 CRYPT_BIT_BLOB *bits;
688 BOOL ret;
690 if (!cbEncoded)
692 SetLastError(E_INVALIDARG);
693 return FALSE;
695 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
696 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
698 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
699 DWORD bytesNeeded = sizeof(WCHAR);
701 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
702 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
703 if (!bits->cbData || bits->cbData > 2)
705 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
706 if (!pbFormat)
707 *pcbFormat = bytesNeeded;
708 else if (*pcbFormat < bytesNeeded)
710 *pcbFormat = bytesNeeded;
711 SetLastError(ERROR_MORE_DATA);
712 ret = FALSE;
714 else
716 LPWSTR str = pbFormat;
718 *pcbFormat = bytesNeeded;
719 strcpyW(str, infoNotAvailable);
722 else
724 static BOOL stringsLoaded = FALSE;
725 int i;
726 DWORD bitStringLen;
727 BOOL first = TRUE;
729 if (!stringsLoaded)
731 for (i = 0;
732 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
733 i++)
734 LoadStringW(hInstance, keyUsageByte0Map[i].id,
735 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
736 for (i = 0;
737 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
738 i++)
739 LoadStringW(hInstance, keyUsageByte1Map[i].id,
740 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
741 stringsLoaded = TRUE;
743 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
744 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
745 NULL, &bitStringLen, &first);
746 bytesNeeded += bitStringLen;
747 if (bits->cbData == 2)
749 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
750 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
751 NULL, &bitStringLen, &first);
752 bytesNeeded += bitStringLen;
754 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
755 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
756 bits->cbData, NULL, &size);
757 bytesNeeded += size;
758 if (!pbFormat)
759 *pcbFormat = bytesNeeded;
760 else if (*pcbFormat < bytesNeeded)
762 *pcbFormat = bytesNeeded;
763 SetLastError(ERROR_MORE_DATA);
764 ret = FALSE;
766 else
768 LPWSTR str = pbFormat;
770 bitStringLen = bytesNeeded;
771 first = TRUE;
772 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
773 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
774 str, &bitStringLen, &first);
775 str += bitStringLen / sizeof(WCHAR) - 1;
776 if (bits->cbData == 2)
778 bitStringLen = bytesNeeded;
779 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
780 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
781 str, &bitStringLen, &first);
782 str += bitStringLen / sizeof(WCHAR) - 1;
784 *str++ = ' ';
785 *str++ = '(';
786 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
787 bits->cbData, str, &size);
788 str += size / sizeof(WCHAR) - 1;
789 *str++ = ')';
790 *str = 0;
793 LocalFree(bits);
795 return ret;
798 static const WCHAR crlf[] = { '\r','\n',0 };
800 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
801 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
802 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
803 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
805 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
806 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
807 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
808 DWORD *pcbFormat)
810 DWORD size;
811 CERT_BASIC_CONSTRAINTS2_INFO *info;
812 BOOL ret;
814 if (!cbEncoded)
816 SetLastError(E_INVALIDARG);
817 return FALSE;
819 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
820 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
822 static const WCHAR pathFmt[] = { '%','d',0 };
823 static BOOL stringsLoaded = FALSE;
824 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
825 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
826 LPCWSTR sep, subjectType;
827 DWORD sepLen;
829 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
831 sep = crlf;
832 sepLen = strlenW(crlf) * sizeof(WCHAR);
834 else
836 sep = commaSpace;
837 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
840 if (!stringsLoaded)
842 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
843 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
844 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
845 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
846 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
847 subjectTypeEndCert,
848 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
849 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
850 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
851 stringsLoaded = TRUE;
853 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
854 if (info->fCA)
855 subjectType = subjectTypeCA;
856 else
857 subjectType = subjectTypeEndCert;
858 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
859 bytesNeeded += sepLen;
860 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
861 if (info->fPathLenConstraint)
862 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
863 else
864 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
865 sizeof(pathLength) / sizeof(pathLength[0]));
866 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
867 if (!pbFormat)
868 *pcbFormat = bytesNeeded;
869 else if (*pcbFormat < bytesNeeded)
871 *pcbFormat = bytesNeeded;
872 SetLastError(ERROR_MORE_DATA);
873 ret = FALSE;
875 else
877 LPWSTR str = pbFormat;
879 *pcbFormat = bytesNeeded;
880 strcpyW(str, subjectTypeHeader);
881 str += strlenW(subjectTypeHeader);
882 strcpyW(str, subjectType);
883 str += strlenW(subjectType);
884 strcpyW(str, sep);
885 str += sepLen / sizeof(WCHAR);
886 strcpyW(str, pathLengthHeader);
887 str += strlenW(pathLengthHeader);
888 strcpyW(str, pathLength);
889 str += strlenW(pathLength);
891 LocalFree(info);
893 return ret;
896 static BOOL CRYPT_FormatHexStringWithPrefix(CRYPT_DATA_BLOB *blob, int id,
897 LPWSTR str, DWORD *pcbStr)
899 WCHAR buf[MAX_STRING_RESOURCE_LEN];
900 DWORD bytesNeeded;
901 BOOL ret;
903 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
904 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
905 blob->pbData, blob->cbData, NULL, &bytesNeeded);
906 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
907 if (!str)
909 *pcbStr = bytesNeeded;
910 ret = TRUE;
912 else if (*pcbStr < bytesNeeded)
914 *pcbStr = bytesNeeded;
915 SetLastError(ERROR_MORE_DATA);
916 ret = FALSE;
918 else
920 *pcbStr = bytesNeeded;
921 strcpyW(str, buf);
922 str += strlenW(str);
923 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
924 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
925 blob->pbData, blob->cbData, str, &bytesNeeded);
927 return ret;
930 static BOOL CRYPT_FormatKeyId(CRYPT_DATA_BLOB *keyId, LPWSTR str,
931 DWORD *pcbStr)
933 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
936 static BOOL CRYPT_FormatCertSerialNumber(CRYPT_DATA_BLOB *serialNum, LPWSTR str,
937 DWORD *pcbStr)
939 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
940 str, pcbStr);
943 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
944 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
946 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
947 CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
949 BOOL ret;
950 WCHAR buf[MAX_STRING_RESOURCE_LEN];
951 WCHAR mask[MAX_STRING_RESOURCE_LEN];
952 WCHAR ipAddrBuf[32];
953 WCHAR maskBuf[16];
954 DWORD bytesNeeded = sizeof(WCHAR);
955 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
957 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
958 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
959 switch (entry->dwAltNameChoice)
961 case CERT_ALT_NAME_RFC822_NAME:
962 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
963 sizeof(buf) / sizeof(buf[0]));
964 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
965 ret = TRUE;
966 break;
967 case CERT_ALT_NAME_DNS_NAME:
968 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
969 sizeof(buf) / sizeof(buf[0]));
970 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
971 ret = TRUE;
972 break;
973 case CERT_ALT_NAME_DIRECTORY_NAME:
975 DWORD directoryNameLen;
977 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
978 strType |= CERT_NAME_STR_CRLF_FLAG;
979 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
980 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
981 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
982 sizeof(buf) / sizeof(buf[0]));
983 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
984 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
985 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
986 else
987 bytesNeeded += sizeof(WCHAR); /* '=' */
988 ret = TRUE;
989 break;
991 case CERT_ALT_NAME_URL:
992 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
993 sizeof(buf) / sizeof(buf[0]));
994 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
995 ret = TRUE;
996 break;
997 case CERT_ALT_NAME_IP_ADDRESS:
999 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1000 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1002 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1003 '.','%','d',0 };
1005 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1006 sizeof(buf) / sizeof(buf[0]));
1007 if (entry->u.IPAddress.cbData == 8)
1009 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1011 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1012 sizeof(mask) / sizeof(mask[0]));
1013 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1014 sprintfW(ipAddrBuf, ipAddrFmt,
1015 entry->u.IPAddress.pbData[0],
1016 entry->u.IPAddress.pbData[1],
1017 entry->u.IPAddress.pbData[2],
1018 entry->u.IPAddress.pbData[3]);
1019 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1020 /* indent again, for the mask line */
1021 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1022 sprintfW(maskBuf, ipAddrFmt,
1023 entry->u.IPAddress.pbData[4],
1024 entry->u.IPAddress.pbData[5],
1025 entry->u.IPAddress.pbData[6],
1026 entry->u.IPAddress.pbData[7]);
1027 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1028 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1030 else
1032 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1033 entry->u.IPAddress.pbData[0],
1034 entry->u.IPAddress.pbData[1],
1035 entry->u.IPAddress.pbData[2],
1036 entry->u.IPAddress.pbData[3],
1037 entry->u.IPAddress.pbData[4],
1038 entry->u.IPAddress.pbData[5],
1039 entry->u.IPAddress.pbData[6],
1040 entry->u.IPAddress.pbData[7]);
1041 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1043 ret = TRUE;
1045 else
1047 FIXME("unknown IP address format (%d bytes)\n",
1048 entry->u.IPAddress.cbData);
1049 ret = FALSE;
1051 break;
1053 default:
1054 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1055 ret = FALSE;
1057 if (ret)
1059 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1060 if (!str)
1061 *pcbStr = bytesNeeded;
1062 else if (*pcbStr < bytesNeeded)
1064 *pcbStr = bytesNeeded;
1065 SetLastError(ERROR_MORE_DATA);
1066 ret = FALSE;
1068 else
1070 DWORD i;
1072 *pcbStr = bytesNeeded;
1073 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1075 for (i = 0; i < indentLevel; i++)
1077 strcpyW(str, indent);
1078 str += strlenW(indent);
1081 strcpyW(str, buf);
1082 str += strlenW(str);
1083 switch (entry->dwAltNameChoice)
1085 case CERT_ALT_NAME_RFC822_NAME:
1086 case CERT_ALT_NAME_DNS_NAME:
1087 case CERT_ALT_NAME_URL:
1088 strcpyW(str, entry->u.pwszURL);
1089 break;
1090 case CERT_ALT_NAME_DIRECTORY_NAME:
1091 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1093 strcpyW(str, colonCrlf);
1094 str += strlenW(colonCrlf);
1096 else
1097 *str++ = '=';
1098 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1099 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1100 bytesNeeded / sizeof(WCHAR));
1101 break;
1102 case CERT_ALT_NAME_IP_ADDRESS:
1103 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1105 strcpyW(str, ipAddrBuf);
1106 str += strlenW(ipAddrBuf);
1107 strcpyW(str, crlf);
1108 str += strlenW(crlf);
1109 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1111 for (i = 0; i < indentLevel; i++)
1113 strcpyW(str, indent);
1114 str += strlenW(indent);
1117 strcpyW(str, mask);
1118 str += strlenW(mask);
1119 strcpyW(str, maskBuf);
1121 else
1122 strcpyW(str, ipAddrBuf);
1123 break;
1127 return ret;
1130 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1131 CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1133 DWORD i, size, bytesNeeded = 0;
1134 BOOL ret = TRUE;
1135 LPCWSTR sep;
1136 DWORD sepLen;
1138 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1140 sep = crlf;
1141 sepLen = strlenW(crlf) * sizeof(WCHAR);
1143 else
1145 sep = commaSpace;
1146 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1149 for (i = 0; ret && i < name->cAltEntry; i++)
1151 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1152 &name->rgAltEntry[i], NULL, &size);
1153 if (ret)
1155 bytesNeeded += size - sizeof(WCHAR);
1156 if (i < name->cAltEntry - 1)
1157 bytesNeeded += sepLen;
1160 if (ret)
1162 bytesNeeded += sizeof(WCHAR);
1163 if (!str)
1164 *pcbStr = bytesNeeded;
1165 else if (*pcbStr < bytesNeeded)
1167 *pcbStr = bytesNeeded;
1168 SetLastError(ERROR_MORE_DATA);
1169 ret = FALSE;
1171 else
1173 *pcbStr = bytesNeeded;
1174 for (i = 0; ret && i < name->cAltEntry; i++)
1176 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1177 &name->rgAltEntry[i], str, &size);
1178 if (ret)
1180 str += size / sizeof(WCHAR) - 1;
1181 if (i < name->cAltEntry - 1)
1183 strcpyW(str, sep);
1184 str += sepLen / sizeof(WCHAR);
1190 return ret;
1193 static const WCHAR colonSep[] = { ':',' ',0 };
1195 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1196 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1197 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1198 DWORD *pcbFormat)
1200 BOOL ret;
1201 CERT_ALT_NAME_INFO *info;
1202 DWORD size;
1204 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1205 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1207 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1208 LocalFree(info);
1210 return ret;
1213 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1214 CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1216 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1217 DWORD bytesNeeded, sepLen;
1218 LPCWSTR sep;
1219 BOOL ret;
1221 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1222 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1223 &bytesNeeded);
1224 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1225 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1227 sep = colonCrlf;
1228 sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1230 else
1232 sep = colonSep;
1233 sepLen = strlenW(colonSep) * sizeof(WCHAR);
1235 bytesNeeded += sepLen;
1236 if (ret)
1238 if (!str)
1239 *pcbStr = bytesNeeded;
1240 else if (*pcbStr < bytesNeeded)
1242 *pcbStr = bytesNeeded;
1243 SetLastError(ERROR_MORE_DATA);
1244 ret = FALSE;
1246 else
1248 *pcbStr = bytesNeeded;
1249 strcpyW(str, buf);
1250 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1251 str += strlenW(str);
1252 strcpyW(str, sep);
1253 str += sepLen / sizeof(WCHAR);
1254 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1255 &bytesNeeded);
1258 return ret;
1261 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1262 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1263 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1264 DWORD *pcbFormat)
1266 CERT_AUTHORITY_KEY_ID2_INFO *info;
1267 DWORD size;
1268 BOOL ret = FALSE;
1270 if (!cbEncoded)
1272 SetLastError(E_INVALIDARG);
1273 return FALSE;
1275 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1276 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1278 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1279 LPCWSTR sep;
1280 DWORD sepLen;
1281 BOOL needSeparator = FALSE;
1283 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1285 sep = crlf;
1286 sepLen = strlenW(crlf) * sizeof(WCHAR);
1288 else
1290 sep = commaSpace;
1291 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1294 if (info->KeyId.cbData)
1296 needSeparator = TRUE;
1297 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1298 if (ret)
1300 /* don't include NULL-terminator more than once */
1301 bytesNeeded += size - sizeof(WCHAR);
1304 if (info->AuthorityCertIssuer.cAltEntry)
1306 if (needSeparator)
1307 bytesNeeded += sepLen;
1308 needSeparator = TRUE;
1309 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1310 &info->AuthorityCertIssuer, NULL, &size);
1311 if (ret)
1313 /* don't include NULL-terminator more than once */
1314 bytesNeeded += size - sizeof(WCHAR);
1317 if (info->AuthorityCertSerialNumber.cbData)
1319 if (needSeparator)
1320 bytesNeeded += sepLen;
1321 ret = CRYPT_FormatCertSerialNumber(
1322 &info->AuthorityCertSerialNumber, NULL, &size);
1323 if (ret)
1325 /* don't include NULL-terminator more than once */
1326 bytesNeeded += size - sizeof(WCHAR);
1329 if (ret)
1331 if (!pbFormat)
1332 *pcbFormat = bytesNeeded;
1333 else if (*pcbFormat < bytesNeeded)
1335 *pcbFormat = bytesNeeded;
1336 SetLastError(ERROR_MORE_DATA);
1337 ret = FALSE;
1339 else
1341 LPWSTR str = pbFormat;
1343 *pcbFormat = bytesNeeded;
1344 needSeparator = FALSE;
1345 if (info->KeyId.cbData)
1347 needSeparator = TRUE;
1348 /* Overestimate size available, it's already been checked
1349 * above.
1351 size = bytesNeeded;
1352 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1353 if (ret)
1354 str += size / sizeof(WCHAR) - 1;
1356 if (info->AuthorityCertIssuer.cAltEntry)
1358 if (needSeparator)
1360 strcpyW(str, sep);
1361 str += sepLen / sizeof(WCHAR);
1363 needSeparator = TRUE;
1364 /* Overestimate size available, it's already been checked
1365 * above.
1367 size = bytesNeeded;
1368 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1369 &info->AuthorityCertIssuer, str, &size);
1370 if (ret)
1371 str += size / sizeof(WCHAR) - 1;
1373 if (info->AuthorityCertSerialNumber.cbData)
1375 if (needSeparator)
1377 strcpyW(str, sep);
1378 str += sepLen / sizeof(WCHAR);
1380 /* Overestimate size available, it's already been checked
1381 * above.
1383 size = bytesNeeded;
1384 ret = CRYPT_FormatCertSerialNumber(
1385 &info->AuthorityCertSerialNumber, str, &size);
1389 LocalFree(info);
1391 return ret;
1394 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1395 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1396 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1397 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1398 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1399 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1401 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1402 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1403 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1404 DWORD *pcbFormat)
1406 CERT_AUTHORITY_INFO_ACCESS *info;
1407 DWORD size;
1408 BOOL ret = FALSE;
1410 if (!cbEncoded)
1412 SetLastError(E_INVALIDARG);
1413 return FALSE;
1415 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1416 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1417 NULL, &info, &size)))
1419 DWORD bytesNeeded = sizeof(WCHAR);
1421 if (!info->cAccDescr)
1423 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1425 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1426 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1427 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1428 if (!pbFormat)
1429 *pcbFormat = bytesNeeded;
1430 else if (*pcbFormat < bytesNeeded)
1432 *pcbFormat = bytesNeeded;
1433 SetLastError(ERROR_MORE_DATA);
1434 ret = FALSE;
1436 else
1438 *pcbFormat = bytesNeeded;
1439 strcpyW((LPWSTR)pbFormat, infoNotAvailable);
1442 else
1444 static const WCHAR numFmt[] = { '%','d',0 };
1445 static const WCHAR equal[] = { '=',0 };
1446 static BOOL stringsLoaded = FALSE;
1447 DWORD i;
1448 LPCWSTR headingSep, accessMethodSep, locationSep;
1449 WCHAR accessDescrNum[11];
1451 if (!stringsLoaded)
1453 LoadStringW(hInstance, IDS_AIA, aia,
1454 sizeof(aia) / sizeof(aia[0]));
1455 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1456 sizeof(accessMethod) / sizeof(accessMethod[0]));
1457 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1458 sizeof(ocsp) / sizeof(ocsp[0]));
1459 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1460 sizeof(caIssuers) / sizeof(caIssuers[0]));
1461 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1462 sizeof(unknown) / sizeof(unknown[0]));
1463 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1464 sizeof(accessLocation) / sizeof(accessLocation[0]));
1465 stringsLoaded = TRUE;
1467 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1469 headingSep = crlf;
1470 accessMethodSep = crlf;
1471 locationSep = colonCrlf;
1473 else
1475 headingSep = colonSep;
1476 accessMethodSep = commaSpace;
1477 locationSep = equal;
1480 for (i = 0; ret && i < info->cAccDescr; i++)
1482 /* Heading */
1483 bytesNeeded += sizeof(WCHAR); /* left bracket */
1484 sprintfW(accessDescrNum, numFmt, i + 1);
1485 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1486 bytesNeeded += sizeof(WCHAR); /* right bracket */
1487 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1488 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1489 /* Access method */
1490 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1491 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1492 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1493 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1494 szOID_PKIX_OCSP))
1495 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1496 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1497 szOID_PKIX_CA_ISSUERS))
1498 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1499 else
1500 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1501 bytesNeeded += sizeof(WCHAR); /* space */
1502 bytesNeeded += sizeof(WCHAR); /* left paren */
1503 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1504 * sizeof(WCHAR);
1505 bytesNeeded += sizeof(WCHAR); /* right paren */
1506 /* Delimiter between access method and location */
1507 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1508 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1509 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1510 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1511 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1512 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1513 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1514 if (ret)
1515 bytesNeeded += size - sizeof(WCHAR);
1516 /* Need extra delimiter between access method entries */
1517 if (i < info->cAccDescr - 1)
1518 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1520 if (ret)
1522 if (!pbFormat)
1523 *pcbFormat = bytesNeeded;
1524 else if (*pcbFormat < bytesNeeded)
1526 *pcbFormat = bytesNeeded;
1527 SetLastError(ERROR_MORE_DATA);
1528 ret = FALSE;
1530 else
1532 LPWSTR str = pbFormat;
1533 DWORD altNameEntrySize;
1535 *pcbFormat = bytesNeeded;
1536 for (i = 0; ret && i < info->cAccDescr; i++)
1538 LPCSTR oidPtr;
1540 *str++ = '[';
1541 sprintfW(accessDescrNum, numFmt, i + 1);
1542 strcpyW(str, accessDescrNum);
1543 str += strlenW(accessDescrNum);
1544 *str++ = ']';
1545 strcpyW(str, aia);
1546 str += strlenW(aia);
1547 strcpyW(str, headingSep);
1548 str += strlenW(headingSep);
1549 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1551 strcpyW(str, indent);
1552 str += strlenW(indent);
1554 strcpyW(str, accessMethod);
1555 str += strlenW(accessMethod);
1556 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1557 szOID_PKIX_OCSP))
1559 strcpyW(str, ocsp);
1560 str += strlenW(ocsp);
1562 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1563 szOID_PKIX_CA_ISSUERS))
1565 strcpyW(str, caIssuers);
1566 str += strlenW(caIssuers);
1568 else
1570 strcpyW(str, unknown);
1571 str += strlenW(unknown);
1573 *str++ = ' ';
1574 *str++ = '(';
1575 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1576 *oidPtr; oidPtr++, str++)
1577 *str = *oidPtr;
1578 *str++ = ')';
1579 strcpyW(str, accessMethodSep);
1580 str += strlenW(accessMethodSep);
1581 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1583 strcpyW(str, indent);
1584 str += strlenW(indent);
1586 strcpyW(str, accessLocation);
1587 str += strlenW(accessLocation);
1588 strcpyW(str, locationSep);
1589 str += strlenW(locationSep);
1590 /* This overestimates the size available, but that
1591 * won't matter since we checked earlier whether enough
1592 * space for the entire string was available.
1594 altNameEntrySize = bytesNeeded;
1595 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1596 &info->rgAccDescr[i].AccessLocation, str,
1597 &altNameEntrySize);
1598 if (ret)
1599 str += altNameEntrySize / sizeof(WCHAR) - 1;
1600 if (i < info->cAccDescr - 1)
1602 strcpyW(str, accessMethodSep);
1603 str += strlenW(accessMethodSep);
1609 LocalFree(info);
1611 return ret;
1614 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1615 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1616 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1617 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1618 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1619 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1621 struct reason_map_entry
1623 BYTE reasonBit;
1624 LPWSTR reason;
1625 int id;
1627 static struct reason_map_entry reason_map[] = {
1628 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1629 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1630 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1631 IDS_REASON_AFFILIATION_CHANGED },
1632 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1633 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1634 IDS_REASON_CESSATION_OF_OPERATION },
1635 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1636 IDS_REASON_CERTIFICATE_HOLD },
1639 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1640 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1642 static const WCHAR sep[] = { ',',' ',0 };
1643 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1644 static BOOL stringsLoaded = FALSE;
1645 int i, numReasons = 0;
1646 BOOL ret = TRUE;
1647 DWORD bytesNeeded = sizeof(WCHAR);
1648 WCHAR bits[6];
1650 if (!stringsLoaded)
1652 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1653 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1654 MAX_STRING_RESOURCE_LEN);
1655 stringsLoaded = TRUE;
1657 /* No need to check reasonFlags->cbData, we already know it's positive.
1658 * Ignore any other bytes, as they're for undefined bits.
1660 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1662 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1664 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1665 if (numReasons++)
1666 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1669 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1670 bytesNeeded += strlenW(bits);
1671 if (!str)
1672 *pcbStr = bytesNeeded;
1673 else if (*pcbStr < bytesNeeded)
1675 *pcbStr = bytesNeeded;
1676 SetLastError(ERROR_MORE_DATA);
1677 ret = FALSE;
1679 else
1681 *pcbStr = bytesNeeded;
1682 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1684 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1686 strcpyW(str, reason_map[i].reason);
1687 str += strlenW(reason_map[i].reason);
1688 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1689 numReasons)
1691 strcpyW(str, sep);
1692 str += strlenW(sep);
1696 strcpyW(str, bits);
1698 return ret;
1701 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1702 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1703 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1704 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1705 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1706 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1708 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1709 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1710 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1711 DWORD *pcbFormat)
1713 CRL_DIST_POINTS_INFO *info;
1714 DWORD size;
1715 BOOL ret = FALSE;
1717 if (!cbEncoded)
1719 SetLastError(E_INVALIDARG);
1720 return FALSE;
1722 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1723 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1725 static const WCHAR numFmt[] = { '%','d',0 };
1726 static const WCHAR commaSep[] = { ',',' ',0 };
1727 static const WCHAR colon[] = { ':',0 };
1728 static BOOL stringsLoaded = FALSE;
1729 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1730 BOOL haveAnEntry = FALSE;
1731 LPCWSTR headingSep, distPointSep, nameSep;
1732 WCHAR distPointNum[11];
1733 DWORD i;
1735 if (!stringsLoaded)
1737 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1738 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1739 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1740 sizeof(distPointName) / sizeof(distPointName[0]));
1741 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1742 sizeof(fullName) / sizeof(fullName[0]));
1743 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1744 sizeof(rdnName) / sizeof(rdnName[0]));
1745 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1746 sizeof(reason) / sizeof(reason[0]));
1747 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1748 sizeof(issuer) / sizeof(issuer[0]));
1749 stringsLoaded = TRUE;
1751 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1753 headingSep = crlf;
1754 distPointSep = crlf;
1755 nameSep = colonCrlf;
1757 else
1759 headingSep = colonSep;
1760 distPointSep = commaSep;
1761 nameSep = colon;
1764 for (i = 0; ret && i < info->cDistPoint; i++)
1766 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1768 if (distPoint->DistPointName.dwDistPointNameChoice !=
1769 CRL_DIST_POINT_NO_NAME)
1771 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1772 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1773 if (distPoint->DistPointName.dwDistPointNameChoice ==
1774 CRL_DIST_POINT_FULL_NAME)
1775 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
1776 else
1777 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
1778 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1779 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1780 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
1781 /* The indent level (3) is higher than when used as the issuer,
1782 * because the name is subordinate to the name type (full vs.
1783 * RDN.)
1785 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
1786 &distPoint->DistPointName.u.FullName, NULL, &size);
1787 if (ret)
1788 bytesNeeded += size - sizeof(WCHAR);
1789 haveAnEntry = TRUE;
1791 else if (distPoint->ReasonFlags.cbData)
1793 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
1794 ret = CRYPT_FormatReason(dwFormatStrType,
1795 &distPoint->ReasonFlags, NULL, &size);
1796 if (ret)
1797 bytesNeeded += size - sizeof(WCHAR);
1798 haveAnEntry = TRUE;
1800 else if (distPoint->CRLIssuer.cAltEntry)
1802 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
1803 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1804 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
1805 &distPoint->CRLIssuer, NULL, &size);
1806 if (ret)
1807 bytesNeeded += size - sizeof(WCHAR);
1808 haveAnEntry = TRUE;
1810 if (haveAnEntry)
1812 bytesNeeded += sizeof(WCHAR); /* left bracket */
1813 sprintfW(distPointNum, numFmt, i + 1);
1814 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
1815 bytesNeeded += sizeof(WCHAR); /* right bracket */
1816 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
1817 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1818 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1819 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1822 if (!haveAnEntry)
1824 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1826 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1827 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1828 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1829 if (!pbFormat)
1830 *pcbFormat = bytesNeeded;
1831 else if (*pcbFormat < bytesNeeded)
1833 *pcbFormat = bytesNeeded;
1834 SetLastError(ERROR_MORE_DATA);
1835 ret = FALSE;
1837 else
1839 *pcbFormat = bytesNeeded;
1840 strcpyW((LPWSTR)pbFormat, infoNotAvailable);
1843 else
1845 if (!pbFormat)
1846 *pcbFormat = bytesNeeded;
1847 else if (*pcbFormat < bytesNeeded)
1849 *pcbFormat = bytesNeeded;
1850 SetLastError(ERROR_MORE_DATA);
1851 ret = FALSE;
1853 else
1855 LPWSTR str = pbFormat;
1857 *pcbFormat = bytesNeeded;
1858 for (i = 0; ret && i < info->cDistPoint; i++)
1860 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1862 *str++ = '[';
1863 sprintfW(distPointNum, numFmt, i + 1);
1864 strcpyW(str, distPointNum);
1865 str += strlenW(distPointNum);
1866 *str++ = ']';
1867 strcpyW(str, crlDistPoint);
1868 str += strlenW(crlDistPoint);
1869 strcpyW(str, headingSep);
1870 str += strlenW(headingSep);
1871 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1873 strcpyW(str, indent);
1874 str += strlenW(indent);
1876 if (distPoint->DistPointName.dwDistPointNameChoice !=
1877 CRL_DIST_POINT_NO_NAME)
1879 DWORD altNameSize = bytesNeeded;
1881 strcpyW(str, distPointName);
1882 str += strlenW(distPointName);
1883 strcpyW(str, nameSep);
1884 str += strlenW(nameSep);
1885 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1887 strcpyW(str, indent);
1888 str += strlenW(indent);
1889 strcpyW(str, indent);
1890 str += strlenW(indent);
1892 if (distPoint->DistPointName.dwDistPointNameChoice ==
1893 CRL_DIST_POINT_FULL_NAME)
1895 strcpyW(str, fullName);
1896 str += strlenW(fullName);
1898 else
1900 strcpyW(str, rdnName);
1901 str += strlenW(rdnName);
1903 strcpyW(str, nameSep);
1904 str += strlenW(nameSep);
1905 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
1906 &distPoint->DistPointName.u.FullName, str,
1907 &altNameSize);
1908 if (ret)
1909 str += altNameSize / sizeof(WCHAR) - 1;
1911 else if (distPoint->ReasonFlags.cbData)
1913 DWORD reasonSize = bytesNeeded;
1915 strcpyW(str, reason);
1916 str += strlenW(reason);
1917 ret = CRYPT_FormatReason(dwFormatStrType,
1918 &distPoint->ReasonFlags, str, &reasonSize);
1919 if (ret)
1920 str += reasonSize / sizeof(WCHAR) - 1;
1922 else if (distPoint->CRLIssuer.cAltEntry)
1924 DWORD crlIssuerSize = bytesNeeded;
1926 strcpyW(str, issuer);
1927 str += strlenW(issuer);
1928 strcpyW(str, nameSep);
1929 str += strlenW(nameSep);
1930 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
1931 &distPoint->CRLIssuer, str,
1932 &crlIssuerSize);
1933 if (ret)
1934 str += crlIssuerSize / sizeof(WCHAR) - 1;
1939 LocalFree(info);
1941 return ret;
1944 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
1945 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1946 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1947 DWORD *pcbFormat)
1949 CERT_ENHKEY_USAGE *usage;
1950 DWORD size;
1951 BOOL ret = FALSE;
1953 if (!cbEncoded)
1955 SetLastError(E_INVALIDARG);
1956 return FALSE;
1958 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
1959 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
1961 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1962 DWORD i;
1963 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1964 LPCWSTR sep;
1965 DWORD sepLen;
1967 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1969 sep = crlf;
1970 sepLen = strlenW(crlf) * sizeof(WCHAR);
1972 else
1974 sep = commaSpace;
1975 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1978 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
1979 sizeof(unknown) / sizeof(unknown[0]));
1980 for (i = 0; i < usage->cUsageIdentifier; i++)
1982 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1983 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1985 if (info)
1986 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
1987 else
1988 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1989 bytesNeeded += sizeof(WCHAR); /* space */
1990 bytesNeeded += sizeof(WCHAR); /* left paren */
1991 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
1992 sizeof(WCHAR);
1993 bytesNeeded += sizeof(WCHAR); /* right paren */
1994 if (i < usage->cUsageIdentifier - 1)
1995 bytesNeeded += sepLen;
1997 if (!pbFormat)
1998 *pcbFormat = bytesNeeded;
1999 else if (*pcbFormat < bytesNeeded)
2001 *pcbFormat = bytesNeeded;
2002 SetLastError(ERROR_MORE_DATA);
2003 ret = FALSE;
2005 else
2007 LPWSTR str = pbFormat;
2009 *pcbFormat = bytesNeeded;
2010 for (i = 0; i < usage->cUsageIdentifier; i++)
2012 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2013 usage->rgpszUsageIdentifier[i],
2014 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2015 LPCSTR oidPtr;
2017 if (info)
2019 strcpyW(str, info->pwszName);
2020 str += strlenW(info->pwszName);
2022 else
2024 strcpyW(str, unknown);
2025 str += strlenW(unknown);
2027 *str++ = ' ';
2028 *str++ = '(';
2029 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2030 *str++ = *oidPtr;
2031 *str++ = ')';
2032 *str = 0;
2033 if (i < usage->cUsageIdentifier - 1)
2035 strcpyW(str, sep);
2036 str += sepLen / sizeof(WCHAR);
2040 LocalFree(usage);
2042 return ret;
2045 static struct BitToString netscapeCertTypeMap[] = {
2046 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2047 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2048 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2049 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2050 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2051 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2052 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2055 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2056 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2057 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2058 DWORD *pcbFormat)
2060 DWORD size;
2061 CRYPT_BIT_BLOB *bits;
2062 BOOL ret;
2064 if (!cbEncoded)
2066 SetLastError(E_INVALIDARG);
2067 return FALSE;
2069 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2070 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2072 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2073 DWORD bytesNeeded = sizeof(WCHAR);
2075 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2076 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2077 if (!bits->cbData || bits->cbData > 1)
2079 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2080 if (!pbFormat)
2081 *pcbFormat = bytesNeeded;
2082 else if (*pcbFormat < bytesNeeded)
2084 *pcbFormat = bytesNeeded;
2085 SetLastError(ERROR_MORE_DATA);
2086 ret = FALSE;
2088 else
2090 LPWSTR str = pbFormat;
2092 *pcbFormat = bytesNeeded;
2093 strcpyW(str, infoNotAvailable);
2096 else
2098 static BOOL stringsLoaded = FALSE;
2099 int i;
2100 DWORD bitStringLen;
2101 BOOL first = TRUE;
2103 if (!stringsLoaded)
2105 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2106 sizeof(netscapeCertTypeMap[0]); i++)
2107 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2108 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2109 stringsLoaded = TRUE;
2111 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2112 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2113 NULL, &bitStringLen, &first);
2114 bytesNeeded += bitStringLen;
2115 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2116 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2117 bits->cbData, NULL, &size);
2118 bytesNeeded += size;
2119 if (!pbFormat)
2120 *pcbFormat = bytesNeeded;
2121 else if (*pcbFormat < bytesNeeded)
2123 *pcbFormat = bytesNeeded;
2124 SetLastError(ERROR_MORE_DATA);
2125 ret = FALSE;
2127 else
2129 LPWSTR str = pbFormat;
2131 bitStringLen = bytesNeeded;
2132 first = TRUE;
2133 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2134 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2135 str, &bitStringLen, &first);
2136 str += bitStringLen / sizeof(WCHAR) - 1;
2137 *str++ = ' ';
2138 *str++ = '(';
2139 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2140 bits->cbData, str, &size);
2141 str += size / sizeof(WCHAR) - 1;
2142 *str++ = ')';
2143 *str = 0;
2146 LocalFree(bits);
2148 return ret;
2151 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2152 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2153 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2154 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2155 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2156 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2158 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2159 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2160 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2161 DWORD *pcbFormat)
2163 SPC_FINANCIAL_CRITERIA criteria;
2164 DWORD size = sizeof(criteria);
2165 BOOL ret = FALSE;
2167 if (!cbEncoded)
2169 SetLastError(E_INVALIDARG);
2170 return FALSE;
2172 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2173 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2174 &size)))
2176 static BOOL stringsLoaded = FALSE;
2177 DWORD bytesNeeded = sizeof(WCHAR);
2178 LPCWSTR sep;
2179 DWORD sepLen;
2181 if (!stringsLoaded)
2183 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2184 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2185 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2186 sizeof(available) / sizeof(available[0]));
2187 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2188 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2189 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2190 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2191 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2192 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2193 stringsLoaded = TRUE;
2195 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2197 sep = crlf;
2198 sepLen = strlenW(crlf) * sizeof(WCHAR);
2200 else
2202 sep = commaSpace;
2203 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2205 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2206 if (criteria.fFinancialInfoAvailable)
2208 bytesNeeded += strlenW(available) * sizeof(WCHAR);
2209 bytesNeeded += sepLen;
2210 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2211 if (criteria.fMeetsCriteria)
2212 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2213 else
2214 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2216 else
2217 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2218 if (!pbFormat)
2219 *pcbFormat = bytesNeeded;
2220 else if (*pcbFormat < bytesNeeded)
2222 *pcbFormat = bytesNeeded;
2223 SetLastError(ERROR_MORE_DATA);
2224 ret = FALSE;
2226 else
2228 LPWSTR str = pbFormat;
2230 *pcbFormat = bytesNeeded;
2231 strcpyW(str, financialCriteria);
2232 str += strlenW(financialCriteria);
2233 if (criteria.fFinancialInfoAvailable)
2235 strcpyW(str, available);
2236 str += strlenW(available);
2237 strcpyW(str, sep);
2238 str += sepLen / sizeof(WCHAR);
2239 strcpyW(str, meetsCriteria);
2240 str += strlenW(meetsCriteria);
2241 if (criteria.fMeetsCriteria)
2242 strcpyW(str, yes);
2243 else
2244 strcpyW(str, no);
2246 else
2248 strcpyW(str, notAvailable);
2249 str += strlenW(notAvailable);
2253 return ret;
2256 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2257 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2259 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2260 DWORD formatStrType, LPCSTR lpszStructType)
2262 CryptFormatObjectFunc format = NULL;
2264 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2266 SetLastError(ERROR_FILE_NOT_FOUND);
2267 return NULL;
2269 if (!HIWORD(lpszStructType))
2271 switch (LOWORD(lpszStructType))
2273 case LOWORD(X509_KEY_USAGE):
2274 format = CRYPT_FormatKeyUsage;
2275 break;
2276 case LOWORD(X509_ALTERNATE_NAME):
2277 format = CRYPT_FormatAltName;
2278 break;
2279 case LOWORD(X509_BASIC_CONSTRAINTS2):
2280 format = CRYPT_FormatBasicConstraints2;
2281 break;
2282 case LOWORD(X509_AUTHORITY_KEY_ID2):
2283 format = CRYPT_FormatAuthorityKeyId2;
2284 break;
2285 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2286 format = CRYPT_FormatAuthorityInfoAccess;
2287 break;
2288 case LOWORD(X509_CRL_DIST_POINTS):
2289 format = CRYPT_FormatCRLDistPoints;
2290 break;
2291 case LOWORD(X509_ENHANCED_KEY_USAGE):
2292 format = CRYPT_FormatEnhancedKeyUsage;
2293 break;
2294 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2295 format = CRYPT_FormatSpcFinancialCriteria;
2296 break;
2299 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2300 format = CRYPT_FormatAltName;
2301 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2302 format = CRYPT_FormatAltName;
2303 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2304 format = CRYPT_FormatKeyUsage;
2305 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2306 format = CRYPT_FormatAltName;
2307 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2308 format = CRYPT_FormatAltName;
2309 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2310 format = CRYPT_FormatBasicConstraints2;
2311 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2312 format = CRYPT_FormatAuthorityInfoAccess;
2313 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2314 format = CRYPT_FormatAuthorityKeyId2;
2315 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2316 format = CRYPT_FormatCRLDistPoints;
2317 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2318 format = CRYPT_FormatEnhancedKeyUsage;
2319 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2320 format = CRYPT_FormatNetscapeCertType;
2321 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2322 format = CRYPT_FormatSpcFinancialCriteria;
2323 return format;
2326 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2327 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2328 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2330 CryptFormatObjectFunc format = NULL;
2331 HCRYPTOIDFUNCADDR hFunc = NULL;
2332 BOOL ret = FALSE;
2334 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2335 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2336 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2338 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2339 dwFormatStrType, lpszStructType)))
2341 static HCRYPTOIDFUNCSET set = NULL;
2343 if (!set)
2344 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2345 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2346 (void **)&format, &hFunc);
2348 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2349 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2350 format = CRYPT_FormatHexString;
2351 if (format)
2352 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2353 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2354 pcbFormat);
2355 if (hFunc)
2356 CryptFreeOIDFunctionAddress(hFunc, 0);
2357 return ret;