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
21 #define NONAMELESSUNION
28 #include "crypt32_private.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)
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)
47 blob->cbData = GetFileSize(file, NULL);
50 blob->pbData = CryptMemAlloc(blob->cbData);
55 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
60 TRACE("returning %d\n", ret);
64 static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
65 DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
66 DWORD *contentType, const void **ppvContext)
70 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
72 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
73 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
74 if (ret && contentType)
75 *contentType = CERT_QUERY_CONTENT_CERT;
77 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
79 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
80 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
81 if (ret && contentType)
82 *contentType = CERT_QUERY_CONTENT_CRL;
84 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
86 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
87 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
88 if (ret && contentType)
89 *contentType = CERT_QUERY_CONTENT_CTL;
94 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
95 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
96 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
97 HCERTSTORE *phCertStore, const void **ppvContext)
100 const CERT_BLOB *blob;
103 DWORD formatType = 0;
105 switch (dwObjectType)
107 case CERT_QUERY_OBJECT_FILE:
108 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
109 * just read the file directly
111 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
114 case CERT_QUERY_OBJECT_BLOB:
119 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
126 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
127 CERT_STORE_CREATE_NEW_FLAG, NULL);
128 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
130 ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
131 pdwContentType, ppvContext);
133 formatType = CERT_QUERY_FORMAT_BINARY;
136 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
138 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
139 CRYPT_DATA_BLOB decoded;
141 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
143 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
144 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
147 decoded.pbData = CryptMemAlloc(decoded.cbData);
150 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
151 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
152 &decoded.cbData, NULL, NULL);
155 ret = CRYPT_QueryContextBlob(&decoded,
156 dwExpectedContentTypeFlags, store, pdwContentType,
159 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
161 CryptMemFree(decoded.pbData);
169 if (pdwMsgAndCertEncodingType)
170 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
172 *pdwFormatType = formatType;
174 *phCertStore = CertDuplicateStore(store);
176 CertCloseStore(store, 0);
177 if (blob == &fileBlob)
178 CryptMemFree(blob->pbData);
179 TRACE("returning %d\n", ret);
183 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
184 const void *pvObject, DWORD dwExpectedContentTypeFlags,
185 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
186 HCERTSTORE *phCertStore, const void **ppvContext)
189 const CERT_BLOB *blob;
190 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
195 switch (dwObjectType)
197 case CERT_QUERY_OBJECT_FILE:
198 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
199 * just read the file directly
201 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
204 case CERT_QUERY_OBJECT_BLOB:
209 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
216 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
217 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
220 DWORD contentType, certStoreOffset;
225 case CERT_STORE_CERTIFICATE_CONTEXT:
226 contextInterface = pCertInterface;
227 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
228 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
229 if (!(dwExpectedContentTypeFlags &
230 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
232 SetLastError(ERROR_INVALID_DATA);
237 case CERT_STORE_CRL_CONTEXT:
238 contextInterface = pCRLInterface;
239 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
240 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
241 if (!(dwExpectedContentTypeFlags &
242 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
244 SetLastError(ERROR_INVALID_DATA);
249 case CERT_STORE_CTL_CONTEXT:
250 contextInterface = pCTLInterface;
251 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
252 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
253 if (!(dwExpectedContentTypeFlags &
254 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
256 SetLastError(ERROR_INVALID_DATA);
262 SetLastError(ERROR_INVALID_DATA);
266 if (pdwMsgAndCertEncodingType)
267 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
269 *pdwContentType = contentType;
271 *phCertStore = CertDuplicateStore(
272 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
274 *ppvContext = contextInterface->duplicate(context);
278 if (contextInterface && context)
279 contextInterface->free(context);
280 if (blob == &fileBlob)
281 CryptMemFree(blob->pbData);
282 TRACE("returning %d\n", ret);
286 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
287 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
288 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
293 TRACE("%s\n", debugstr_w(fileName));
294 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
295 OPEN_EXISTING, 0, NULL);
296 if (file != INVALID_HANDLE_VALUE)
298 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
299 CERT_STORE_CREATE_NEW_FLAG, NULL);
301 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
304 if (pdwMsgAndCertEncodingType)
305 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
307 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
309 *phCertStore = CertDuplicateStore(store);
311 CertCloseStore(store, 0);
314 TRACE("returning %d\n", ret);
318 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
319 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
320 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
322 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
323 CERT_STORE_CREATE_NEW_FLAG, NULL);
326 TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
328 ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
331 if (pdwMsgAndCertEncodingType)
332 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
334 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
336 *phCertStore = CertDuplicateStore(store);
338 CertCloseStore(store, 0);
339 TRACE("returning %d\n", ret);
343 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
344 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
345 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
347 switch (dwObjectType)
349 case CERT_QUERY_OBJECT_FILE:
350 return CRYPT_QuerySerializedStoreFromFile(pvObject,
351 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
352 case CERT_QUERY_OBJECT_BLOB:
353 return CRYPT_QuerySerializedStoreFromBlob(pvObject,
354 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
356 FIXME("unimplemented for type %d\n", dwObjectType);
357 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
362 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
363 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
365 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
369 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
371 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
374 DWORD type, len = sizeof(type);
376 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
379 if (type != CMSG_SIGNED)
381 SetLastError(ERROR_INVALID_DATA);
389 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
393 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
404 if (pdwMsgAndCertEncodingType)
405 *pdwMsgAndCertEncodingType = encodingType;
407 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
414 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
415 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
417 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
421 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
423 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
426 DWORD type, len = sizeof(type);
428 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
431 if (type != CMSG_DATA)
433 SetLastError(ERROR_INVALID_DATA);
441 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
445 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
456 if (pdwMsgAndCertEncodingType)
457 *pdwMsgAndCertEncodingType = encodingType;
459 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
466 /* Used to decode non-embedded messages */
467 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
468 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
469 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
470 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
473 const CERT_BLOB *blob;
475 HCRYPTMSG msg = NULL;
476 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
477 DWORD formatType = 0;
479 TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
480 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
481 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
484 switch (dwObjectType)
486 case CERT_QUERY_OBJECT_FILE:
487 /* This isn't an embedded PKCS7 message, so just read the file
490 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
493 case CERT_QUERY_OBJECT_BLOB:
498 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
505 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
507 /* Try it first as a signed message */
508 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
509 ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
510 pdwContentType, &msg);
511 /* Failing that, try as an unsigned message */
513 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
514 ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
515 pdwContentType, &msg);
517 formatType = CERT_QUERY_FORMAT_BINARY;
520 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
522 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
523 CRYPT_DATA_BLOB decoded;
525 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
527 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
528 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
531 decoded.pbData = CryptMemAlloc(decoded.cbData);
534 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
535 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
536 &decoded.cbData, NULL, NULL);
539 /* Try it first as a signed message */
540 if (dwExpectedContentTypeFlags &
541 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
542 ret = CRYPT_QuerySignedMessage(&decoded,
543 pdwMsgAndCertEncodingType, pdwContentType, &msg);
544 /* Failing that, try as an unsigned message */
545 if (!ret && (dwExpectedContentTypeFlags &
546 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
547 ret = CRYPT_QueryUnsignedMessage(&decoded,
548 pdwMsgAndCertEncodingType, pdwContentType, &msg);
550 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
552 CryptMemFree(decoded.pbData);
557 if (!ret && !(blob->cbData % sizeof(WCHAR)))
559 CRYPT_DATA_BLOB decoded;
560 LPWSTR str = (LPWSTR)blob->pbData;
561 DWORD strLen = blob->cbData / sizeof(WCHAR);
563 /* Try again, assuming the input string is UTF-16 base64 */
564 while (strLen && !str[strLen - 1])
566 ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
567 NULL, &decoded.cbData, NULL, NULL);
570 decoded.pbData = CryptMemAlloc(decoded.cbData);
573 ret = CryptStringToBinaryW(str, strLen,
574 CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
578 /* Try it first as a signed message */
579 if (dwExpectedContentTypeFlags &
580 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
581 ret = CRYPT_QuerySignedMessage(&decoded,
582 pdwMsgAndCertEncodingType, pdwContentType, &msg);
583 /* Failing that, try as an unsigned message */
584 if (!ret && (dwExpectedContentTypeFlags &
585 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
586 ret = CRYPT_QueryUnsignedMessage(&decoded,
587 pdwMsgAndCertEncodingType, pdwContentType, &msg);
589 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
591 CryptMemFree(decoded.pbData);
601 *pdwFormatType = formatType;
603 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
610 if (blob == &fileBlob)
611 CryptMemFree(blob->pbData);
612 TRACE("returning %d\n", ret);
616 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
617 const void *pvObject, DWORD dwExpectedContentTypeFlags,
618 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
619 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
625 TRACE("%s\n", debugstr_w(pvObject));
627 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
629 WARN("don't know what to do for type %d embedded signed messages\n",
631 SetLastError(E_INVALIDARG);
634 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
635 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
636 if (file != INVALID_HANDLE_VALUE)
638 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
641 SIP_DISPATCH_INFO sip;
643 memset(&sip, 0, sizeof(sip));
644 sip.cbSize = sizeof(sip);
645 ret = CryptSIPLoad(&subject, 0, &sip);
648 SIP_SUBJECTINFO subjectInfo;
652 memset(&subjectInfo, 0, sizeof(subjectInfo));
653 subjectInfo.cbSize = sizeof(subjectInfo);
654 subjectInfo.pgSubjectType = &subject;
655 subjectInfo.hFile = file;
656 subjectInfo.pwsFileName = pvObject;
657 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
661 blob.pbData = CryptMemAlloc(blob.cbData);
664 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
665 &blob.cbData, blob.pbData);
668 ret = CRYPT_QueryMessageObject(
669 CERT_QUERY_OBJECT_BLOB, &blob,
670 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
671 CERT_QUERY_FORMAT_FLAG_BINARY,
672 pdwMsgAndCertEncodingType, NULL, NULL,
674 if (ret && pdwContentType)
675 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
677 CryptMemFree(blob.pbData);
681 SetLastError(ERROR_OUTOFMEMORY);
689 TRACE("returning %d\n", ret);
693 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
694 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
695 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
696 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
697 const void **ppvContext)
699 static const DWORD unimplementedTypes =
700 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
701 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
704 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
705 dwObjectType, pvObject, dwExpectedContentTypeFlags,
706 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
707 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
709 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
710 dwObjectType != CERT_QUERY_OBJECT_FILE)
712 WARN("unsupported type %d\n", dwObjectType);
713 SetLastError(E_INVALIDARG);
718 WARN("missing required argument\n");
719 SetLastError(E_INVALIDARG);
722 if (dwExpectedContentTypeFlags & unimplementedTypes)
723 WARN("unimplemented for types %08x\n",
724 dwExpectedContentTypeFlags & unimplementedTypes);
727 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
736 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
737 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
738 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
740 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
741 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
742 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
746 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
748 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
749 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
752 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
753 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
754 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
756 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
757 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
758 phCertStore, ppvContext);
761 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
762 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
764 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
765 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
766 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
770 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
772 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
773 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
777 SetLastError(CRYPT_E_NO_MATCH);
778 TRACE("returning %d\n", ret);
782 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
783 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
784 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
791 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
793 bytesNeeded = sizeof(WCHAR);
796 *pcbFormat = bytesNeeded;
799 else if (*pcbFormat < bytesNeeded)
801 *pcbFormat = bytesNeeded;
802 SetLastError(ERROR_MORE_DATA);
807 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
808 static const WCHAR endFmt[] = { '%','0','2','x',0 };
810 LPWSTR ptr = pbFormat;
812 *pcbFormat = bytesNeeded;
815 for (i = 0; i < cbEncoded; i++)
817 if (i < cbEncoded - 1)
818 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
820 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
830 #define MAX_STRING_RESOURCE_LEN 128
832 static const WCHAR commaSpace[] = { ',',' ',0 };
838 WCHAR str[MAX_STRING_RESOURCE_LEN];
841 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
842 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
844 DWORD bytesNeeded = sizeof(WCHAR);
846 BOOL ret = TRUE, localFirst = *first;
848 for (i = 0; i < mapEntries; i++)
849 if (bits & map[i].bit)
852 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
854 bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
859 *pcbFormat = bytesNeeded;
861 else if (*pcbFormat < bytesNeeded)
864 *pcbFormat = bytesNeeded;
865 SetLastError(ERROR_MORE_DATA);
870 LPWSTR str = pbFormat;
873 *pcbFormat = bytesNeeded;
874 for (i = 0; i < mapEntries; i++)
875 if (bits & map[i].bit)
879 strcpyW(str, commaSpace);
880 str += strlenW(commaSpace);
883 strcpyW(str, map[i].str);
884 str += strlenW(map[i].str);
891 static struct BitToString keyUsageByte0Map[] = {
892 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
893 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
894 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
895 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
896 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
897 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
898 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
899 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
900 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
902 static struct BitToString keyUsageByte1Map[] = {
903 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
906 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
907 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
908 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
912 CRYPT_BIT_BLOB *bits;
917 SetLastError(E_INVALIDARG);
920 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
921 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
923 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
924 DWORD bytesNeeded = sizeof(WCHAR);
926 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
927 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
928 if (!bits->cbData || bits->cbData > 2)
930 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
932 *pcbFormat = bytesNeeded;
933 else if (*pcbFormat < bytesNeeded)
935 *pcbFormat = bytesNeeded;
936 SetLastError(ERROR_MORE_DATA);
941 LPWSTR str = pbFormat;
943 *pcbFormat = bytesNeeded;
944 strcpyW(str, infoNotAvailable);
949 static BOOL stringsLoaded = FALSE;
957 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
959 LoadStringW(hInstance, keyUsageByte0Map[i].id,
960 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
962 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
964 LoadStringW(hInstance, keyUsageByte1Map[i].id,
965 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
966 stringsLoaded = TRUE;
968 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
969 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
970 NULL, &bitStringLen, &first);
971 bytesNeeded += bitStringLen;
972 if (bits->cbData == 2)
974 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
975 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
976 NULL, &bitStringLen, &first);
977 bytesNeeded += bitStringLen;
979 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
980 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
981 bits->cbData, NULL, &size);
984 *pcbFormat = bytesNeeded;
985 else if (*pcbFormat < bytesNeeded)
987 *pcbFormat = bytesNeeded;
988 SetLastError(ERROR_MORE_DATA);
993 LPWSTR str = pbFormat;
995 bitStringLen = bytesNeeded;
997 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
998 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
999 str, &bitStringLen, &first);
1000 str += bitStringLen / sizeof(WCHAR) - 1;
1001 if (bits->cbData == 2)
1003 bitStringLen = bytesNeeded;
1004 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
1005 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
1006 str, &bitStringLen, &first);
1007 str += bitStringLen / sizeof(WCHAR) - 1;
1011 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1012 bits->cbData, str, &size);
1013 str += size / sizeof(WCHAR) - 1;
1023 static const WCHAR crlf[] = { '\r','\n',0 };
1025 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1026 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1027 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1028 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1030 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1031 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1032 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1036 CERT_BASIC_CONSTRAINTS2_INFO *info;
1041 SetLastError(E_INVALIDARG);
1044 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1045 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1047 static const WCHAR pathFmt[] = { '%','d',0 };
1048 static BOOL stringsLoaded = FALSE;
1049 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1050 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1051 LPCWSTR sep, subjectType;
1054 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1057 sepLen = strlenW(crlf) * sizeof(WCHAR);
1062 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1067 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
1068 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
1069 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
1070 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
1071 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
1073 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
1074 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
1075 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
1076 stringsLoaded = TRUE;
1078 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
1080 subjectType = subjectTypeCA;
1082 subjectType = subjectTypeEndCert;
1083 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
1084 bytesNeeded += sepLen;
1085 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
1086 if (info->fPathLenConstraint)
1087 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
1089 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
1090 sizeof(pathLength) / sizeof(pathLength[0]));
1091 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
1093 *pcbFormat = bytesNeeded;
1094 else if (*pcbFormat < bytesNeeded)
1096 *pcbFormat = bytesNeeded;
1097 SetLastError(ERROR_MORE_DATA);
1102 LPWSTR str = pbFormat;
1104 *pcbFormat = bytesNeeded;
1105 strcpyW(str, subjectTypeHeader);
1106 str += strlenW(subjectTypeHeader);
1107 strcpyW(str, subjectType);
1108 str += strlenW(subjectType);
1110 str += sepLen / sizeof(WCHAR);
1111 strcpyW(str, pathLengthHeader);
1112 str += strlenW(pathLengthHeader);
1113 strcpyW(str, pathLength);
1114 str += strlenW(pathLength);
1121 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1122 LPWSTR str, DWORD *pcbStr)
1124 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1128 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1129 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1130 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1131 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1134 *pcbStr = bytesNeeded;
1137 else if (*pcbStr < bytesNeeded)
1139 *pcbStr = bytesNeeded;
1140 SetLastError(ERROR_MORE_DATA);
1145 *pcbStr = bytesNeeded;
1147 str += strlenW(str);
1148 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1149 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1150 blob->pbData, blob->cbData, str, &bytesNeeded);
1155 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1158 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1161 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1164 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1168 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
1169 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
1171 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1172 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1175 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1176 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1177 WCHAR ipAddrBuf[32];
1179 DWORD bytesNeeded = sizeof(WCHAR);
1180 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1182 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1183 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1184 switch (entry->dwAltNameChoice)
1186 case CERT_ALT_NAME_RFC822_NAME:
1187 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
1188 sizeof(buf) / sizeof(buf[0]));
1189 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
1192 case CERT_ALT_NAME_DNS_NAME:
1193 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
1194 sizeof(buf) / sizeof(buf[0]));
1195 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
1198 case CERT_ALT_NAME_DIRECTORY_NAME:
1200 DWORD directoryNameLen;
1202 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1203 strType |= CERT_NAME_STR_CRLF_FLAG;
1204 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1205 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
1206 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
1207 sizeof(buf) / sizeof(buf[0]));
1208 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1209 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1210 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
1212 bytesNeeded += sizeof(WCHAR); /* '=' */
1216 case CERT_ALT_NAME_URL:
1217 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
1218 sizeof(buf) / sizeof(buf[0]));
1219 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
1222 case CERT_ALT_NAME_IP_ADDRESS:
1224 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1225 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1227 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1230 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1231 sizeof(buf) / sizeof(buf[0]));
1232 if (entry->u.IPAddress.cbData == 8)
1234 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1236 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1237 sizeof(mask) / sizeof(mask[0]));
1238 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1239 sprintfW(ipAddrBuf, ipAddrFmt,
1240 entry->u.IPAddress.pbData[0],
1241 entry->u.IPAddress.pbData[1],
1242 entry->u.IPAddress.pbData[2],
1243 entry->u.IPAddress.pbData[3]);
1244 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1245 /* indent again, for the mask line */
1246 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1247 sprintfW(maskBuf, ipAddrFmt,
1248 entry->u.IPAddress.pbData[4],
1249 entry->u.IPAddress.pbData[5],
1250 entry->u.IPAddress.pbData[6],
1251 entry->u.IPAddress.pbData[7]);
1252 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1253 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1257 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1258 entry->u.IPAddress.pbData[0],
1259 entry->u.IPAddress.pbData[1],
1260 entry->u.IPAddress.pbData[2],
1261 entry->u.IPAddress.pbData[3],
1262 entry->u.IPAddress.pbData[4],
1263 entry->u.IPAddress.pbData[5],
1264 entry->u.IPAddress.pbData[6],
1265 entry->u.IPAddress.pbData[7]);
1266 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1272 FIXME("unknown IP address format (%d bytes)\n",
1273 entry->u.IPAddress.cbData);
1279 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1284 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1286 *pcbStr = bytesNeeded;
1287 else if (*pcbStr < bytesNeeded)
1289 *pcbStr = bytesNeeded;
1290 SetLastError(ERROR_MORE_DATA);
1297 *pcbStr = bytesNeeded;
1298 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1300 for (i = 0; i < indentLevel; i++)
1302 strcpyW(str, indent);
1303 str += strlenW(indent);
1307 str += strlenW(str);
1308 switch (entry->dwAltNameChoice)
1310 case CERT_ALT_NAME_RFC822_NAME:
1311 case CERT_ALT_NAME_DNS_NAME:
1312 case CERT_ALT_NAME_URL:
1313 strcpyW(str, entry->u.pwszURL);
1315 case CERT_ALT_NAME_DIRECTORY_NAME:
1316 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1318 strcpyW(str, colonCrlf);
1319 str += strlenW(colonCrlf);
1323 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1324 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1325 bytesNeeded / sizeof(WCHAR));
1327 case CERT_ALT_NAME_IP_ADDRESS:
1328 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1330 strcpyW(str, ipAddrBuf);
1331 str += strlenW(ipAddrBuf);
1333 str += strlenW(crlf);
1334 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1336 for (i = 0; i < indentLevel; i++)
1338 strcpyW(str, indent);
1339 str += strlenW(indent);
1343 str += strlenW(mask);
1344 strcpyW(str, maskBuf);
1347 strcpyW(str, ipAddrBuf);
1355 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1356 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1358 DWORD i, size, bytesNeeded = 0;
1363 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1366 sepLen = strlenW(crlf) * sizeof(WCHAR);
1371 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1374 for (i = 0; ret && i < name->cAltEntry; i++)
1376 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1377 &name->rgAltEntry[i], NULL, &size);
1380 bytesNeeded += size - sizeof(WCHAR);
1381 if (i < name->cAltEntry - 1)
1382 bytesNeeded += sepLen;
1387 bytesNeeded += sizeof(WCHAR);
1389 *pcbStr = bytesNeeded;
1390 else if (*pcbStr < bytesNeeded)
1392 *pcbStr = bytesNeeded;
1393 SetLastError(ERROR_MORE_DATA);
1398 *pcbStr = bytesNeeded;
1399 for (i = 0; ret && i < name->cAltEntry; i++)
1401 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1402 &name->rgAltEntry[i], str, &size);
1405 str += size / sizeof(WCHAR) - 1;
1406 if (i < name->cAltEntry - 1)
1409 str += sepLen / sizeof(WCHAR);
1418 static const WCHAR colonSep[] = { ':',' ',0 };
1420 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1421 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1422 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1426 CERT_ALT_NAME_INFO *info;
1429 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1430 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1432 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1438 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1439 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1441 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1442 DWORD bytesNeeded, sepLen;
1446 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1447 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1449 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1450 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1453 sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1458 sepLen = strlenW(colonSep) * sizeof(WCHAR);
1460 bytesNeeded += sepLen;
1464 *pcbStr = bytesNeeded;
1465 else if (*pcbStr < bytesNeeded)
1467 *pcbStr = bytesNeeded;
1468 SetLastError(ERROR_MORE_DATA);
1473 *pcbStr = bytesNeeded;
1475 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1476 str += strlenW(str);
1478 str += sepLen / sizeof(WCHAR);
1479 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1486 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1487 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1488 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1491 CERT_AUTHORITY_KEY_ID2_INFO *info;
1497 SetLastError(E_INVALIDARG);
1500 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1501 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1503 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1506 BOOL needSeparator = FALSE;
1508 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1511 sepLen = strlenW(crlf) * sizeof(WCHAR);
1516 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1519 if (info->KeyId.cbData)
1521 needSeparator = TRUE;
1522 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1525 /* don't include NULL-terminator more than once */
1526 bytesNeeded += size - sizeof(WCHAR);
1529 if (info->AuthorityCertIssuer.cAltEntry)
1532 bytesNeeded += sepLen;
1533 needSeparator = TRUE;
1534 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1535 &info->AuthorityCertIssuer, NULL, &size);
1538 /* don't include NULL-terminator more than once */
1539 bytesNeeded += size - sizeof(WCHAR);
1542 if (info->AuthorityCertSerialNumber.cbData)
1545 bytesNeeded += sepLen;
1546 ret = CRYPT_FormatCertSerialNumber(
1547 &info->AuthorityCertSerialNumber, NULL, &size);
1550 /* don't include NULL-terminator more than once */
1551 bytesNeeded += size - sizeof(WCHAR);
1557 *pcbFormat = bytesNeeded;
1558 else if (*pcbFormat < bytesNeeded)
1560 *pcbFormat = bytesNeeded;
1561 SetLastError(ERROR_MORE_DATA);
1566 LPWSTR str = pbFormat;
1568 *pcbFormat = bytesNeeded;
1569 needSeparator = FALSE;
1570 if (info->KeyId.cbData)
1572 needSeparator = TRUE;
1573 /* Overestimate size available, it's already been checked
1577 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1579 str += size / sizeof(WCHAR) - 1;
1581 if (info->AuthorityCertIssuer.cAltEntry)
1586 str += sepLen / sizeof(WCHAR);
1588 needSeparator = TRUE;
1589 /* Overestimate size available, it's already been checked
1593 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1594 &info->AuthorityCertIssuer, str, &size);
1596 str += size / sizeof(WCHAR) - 1;
1598 if (info->AuthorityCertSerialNumber.cbData)
1603 str += sepLen / sizeof(WCHAR);
1605 /* Overestimate size available, it's already been checked
1609 ret = CRYPT_FormatCertSerialNumber(
1610 &info->AuthorityCertSerialNumber, str, &size);
1619 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1620 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1621 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1622 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1623 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1624 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1626 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1627 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1628 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1631 CERT_AUTHORITY_INFO_ACCESS *info;
1637 SetLastError(E_INVALIDARG);
1640 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1641 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1642 NULL, &info, &size)))
1644 DWORD bytesNeeded = sizeof(WCHAR);
1646 if (!info->cAccDescr)
1648 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1650 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1651 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1652 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1654 *pcbFormat = bytesNeeded;
1655 else if (*pcbFormat < bytesNeeded)
1657 *pcbFormat = bytesNeeded;
1658 SetLastError(ERROR_MORE_DATA);
1663 *pcbFormat = bytesNeeded;
1664 strcpyW(pbFormat, infoNotAvailable);
1669 static const WCHAR numFmt[] = { '%','d',0 };
1670 static const WCHAR equal[] = { '=',0 };
1671 static BOOL stringsLoaded = FALSE;
1673 LPCWSTR headingSep, accessMethodSep, locationSep;
1674 WCHAR accessDescrNum[11];
1678 LoadStringW(hInstance, IDS_AIA, aia,
1679 sizeof(aia) / sizeof(aia[0]));
1680 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1681 sizeof(accessMethod) / sizeof(accessMethod[0]));
1682 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1683 sizeof(ocsp) / sizeof(ocsp[0]));
1684 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1685 sizeof(caIssuers) / sizeof(caIssuers[0]));
1686 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1687 sizeof(unknown) / sizeof(unknown[0]));
1688 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1689 sizeof(accessLocation) / sizeof(accessLocation[0]));
1690 stringsLoaded = TRUE;
1692 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1695 accessMethodSep = crlf;
1696 locationSep = colonCrlf;
1700 headingSep = colonSep;
1701 accessMethodSep = commaSpace;
1702 locationSep = equal;
1705 for (i = 0; ret && i < info->cAccDescr; i++)
1708 bytesNeeded += sizeof(WCHAR); /* left bracket */
1709 sprintfW(accessDescrNum, numFmt, i + 1);
1710 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1711 bytesNeeded += sizeof(WCHAR); /* right bracket */
1712 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1713 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1715 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1716 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1717 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1718 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1720 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1721 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1722 szOID_PKIX_CA_ISSUERS))
1723 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1725 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1726 bytesNeeded += sizeof(WCHAR); /* space */
1727 bytesNeeded += sizeof(WCHAR); /* left paren */
1728 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1730 bytesNeeded += sizeof(WCHAR); /* right paren */
1731 /* Delimiter between access method and location */
1732 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1733 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1734 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1735 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1736 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1737 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1738 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1740 bytesNeeded += size - sizeof(WCHAR);
1741 /* Need extra delimiter between access method entries */
1742 if (i < info->cAccDescr - 1)
1743 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1748 *pcbFormat = bytesNeeded;
1749 else if (*pcbFormat < bytesNeeded)
1751 *pcbFormat = bytesNeeded;
1752 SetLastError(ERROR_MORE_DATA);
1757 LPWSTR str = pbFormat;
1758 DWORD altNameEntrySize;
1760 *pcbFormat = bytesNeeded;
1761 for (i = 0; ret && i < info->cAccDescr; i++)
1766 sprintfW(accessDescrNum, numFmt, i + 1);
1767 strcpyW(str, accessDescrNum);
1768 str += strlenW(accessDescrNum);
1771 str += strlenW(aia);
1772 strcpyW(str, headingSep);
1773 str += strlenW(headingSep);
1774 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1776 strcpyW(str, indent);
1777 str += strlenW(indent);
1779 strcpyW(str, accessMethod);
1780 str += strlenW(accessMethod);
1781 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1785 str += strlenW(ocsp);
1787 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1788 szOID_PKIX_CA_ISSUERS))
1790 strcpyW(str, caIssuers);
1791 str += strlenW(caIssuers);
1795 strcpyW(str, unknown);
1796 str += strlenW(unknown);
1800 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1801 *oidPtr; oidPtr++, str++)
1804 strcpyW(str, accessMethodSep);
1805 str += strlenW(accessMethodSep);
1806 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1808 strcpyW(str, indent);
1809 str += strlenW(indent);
1811 strcpyW(str, accessLocation);
1812 str += strlenW(accessLocation);
1813 strcpyW(str, locationSep);
1814 str += strlenW(locationSep);
1815 /* This overestimates the size available, but that
1816 * won't matter since we checked earlier whether enough
1817 * space for the entire string was available.
1819 altNameEntrySize = bytesNeeded;
1820 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1821 &info->rgAccDescr[i].AccessLocation, str,
1824 str += altNameEntrySize / sizeof(WCHAR) - 1;
1825 if (i < info->cAccDescr - 1)
1827 strcpyW(str, accessMethodSep);
1828 str += strlenW(accessMethodSep);
1839 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1840 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1841 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1842 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1843 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1844 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1846 struct reason_map_entry
1852 static struct reason_map_entry reason_map[] = {
1853 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1854 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1855 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1856 IDS_REASON_AFFILIATION_CHANGED },
1857 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1858 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1859 IDS_REASON_CESSATION_OF_OPERATION },
1860 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1861 IDS_REASON_CERTIFICATE_HOLD },
1864 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1865 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1867 static const WCHAR sep[] = { ',',' ',0 };
1868 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1869 static BOOL stringsLoaded = FALSE;
1870 int i, numReasons = 0;
1872 DWORD bytesNeeded = sizeof(WCHAR);
1877 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1878 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1879 MAX_STRING_RESOURCE_LEN);
1880 stringsLoaded = TRUE;
1882 /* No need to check reasonFlags->cbData, we already know it's positive.
1883 * Ignore any other bytes, as they're for undefined bits.
1885 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1887 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1889 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1891 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1894 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1895 bytesNeeded += strlenW(bits);
1897 *pcbStr = bytesNeeded;
1898 else if (*pcbStr < bytesNeeded)
1900 *pcbStr = bytesNeeded;
1901 SetLastError(ERROR_MORE_DATA);
1906 *pcbStr = bytesNeeded;
1907 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1909 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1911 strcpyW(str, reason_map[i].reason);
1912 str += strlenW(reason_map[i].reason);
1913 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1917 str += strlenW(sep);
1926 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1927 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1928 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1929 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1930 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1931 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1933 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1934 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1935 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1938 CRL_DIST_POINTS_INFO *info;
1944 SetLastError(E_INVALIDARG);
1947 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1948 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1950 static const WCHAR numFmt[] = { '%','d',0 };
1951 static const WCHAR colon[] = { ':',0 };
1952 static BOOL stringsLoaded = FALSE;
1953 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1954 BOOL haveAnEntry = FALSE;
1955 LPCWSTR headingSep, nameSep;
1956 WCHAR distPointNum[11];
1961 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1962 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1963 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1964 sizeof(distPointName) / sizeof(distPointName[0]));
1965 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1966 sizeof(fullName) / sizeof(fullName[0]));
1967 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1968 sizeof(rdnName) / sizeof(rdnName[0]));
1969 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1970 sizeof(reason) / sizeof(reason[0]));
1971 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1972 sizeof(issuer) / sizeof(issuer[0]));
1973 stringsLoaded = TRUE;
1975 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1978 nameSep = colonCrlf;
1982 headingSep = colonSep;
1986 for (i = 0; ret && i < info->cDistPoint; i++)
1988 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1990 if (distPoint->DistPointName.dwDistPointNameChoice !=
1991 CRL_DIST_POINT_NO_NAME)
1993 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1994 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1995 if (distPoint->DistPointName.dwDistPointNameChoice ==
1996 CRL_DIST_POINT_FULL_NAME)
1997 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
1999 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
2000 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2001 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2002 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
2003 /* The indent level (3) is higher than when used as the issuer,
2004 * because the name is subordinate to the name type (full vs.
2007 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2008 &distPoint->DistPointName.u.FullName, NULL, &size);
2010 bytesNeeded += size - sizeof(WCHAR);
2013 else if (distPoint->ReasonFlags.cbData)
2015 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
2016 ret = CRYPT_FormatReason(dwFormatStrType,
2017 &distPoint->ReasonFlags, NULL, &size);
2019 bytesNeeded += size - sizeof(WCHAR);
2022 else if (distPoint->CRLIssuer.cAltEntry)
2024 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
2025 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2026 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2027 &distPoint->CRLIssuer, NULL, &size);
2029 bytesNeeded += size - sizeof(WCHAR);
2034 bytesNeeded += sizeof(WCHAR); /* left bracket */
2035 sprintfW(distPointNum, numFmt, i + 1);
2036 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
2037 bytesNeeded += sizeof(WCHAR); /* right bracket */
2038 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
2039 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
2040 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2041 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
2046 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2048 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2049 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2050 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2052 *pcbFormat = bytesNeeded;
2053 else if (*pcbFormat < bytesNeeded)
2055 *pcbFormat = bytesNeeded;
2056 SetLastError(ERROR_MORE_DATA);
2061 *pcbFormat = bytesNeeded;
2062 strcpyW(pbFormat, infoNotAvailable);
2068 *pcbFormat = bytesNeeded;
2069 else if (*pcbFormat < bytesNeeded)
2071 *pcbFormat = bytesNeeded;
2072 SetLastError(ERROR_MORE_DATA);
2077 LPWSTR str = pbFormat;
2079 *pcbFormat = bytesNeeded;
2080 for (i = 0; ret && i < info->cDistPoint; i++)
2082 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2085 sprintfW(distPointNum, numFmt, i + 1);
2086 strcpyW(str, distPointNum);
2087 str += strlenW(distPointNum);
2089 strcpyW(str, crlDistPoint);
2090 str += strlenW(crlDistPoint);
2091 strcpyW(str, headingSep);
2092 str += strlenW(headingSep);
2093 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2095 strcpyW(str, indent);
2096 str += strlenW(indent);
2098 if (distPoint->DistPointName.dwDistPointNameChoice !=
2099 CRL_DIST_POINT_NO_NAME)
2101 DWORD altNameSize = bytesNeeded;
2103 strcpyW(str, distPointName);
2104 str += strlenW(distPointName);
2105 strcpyW(str, nameSep);
2106 str += strlenW(nameSep);
2107 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2109 strcpyW(str, indent);
2110 str += strlenW(indent);
2111 strcpyW(str, indent);
2112 str += strlenW(indent);
2114 if (distPoint->DistPointName.dwDistPointNameChoice ==
2115 CRL_DIST_POINT_FULL_NAME)
2117 strcpyW(str, fullName);
2118 str += strlenW(fullName);
2122 strcpyW(str, rdnName);
2123 str += strlenW(rdnName);
2125 strcpyW(str, nameSep);
2126 str += strlenW(nameSep);
2127 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2128 &distPoint->DistPointName.u.FullName, str,
2131 str += altNameSize / sizeof(WCHAR) - 1;
2133 else if (distPoint->ReasonFlags.cbData)
2135 DWORD reasonSize = bytesNeeded;
2137 strcpyW(str, reason);
2138 str += strlenW(reason);
2139 ret = CRYPT_FormatReason(dwFormatStrType,
2140 &distPoint->ReasonFlags, str, &reasonSize);
2142 str += reasonSize / sizeof(WCHAR) - 1;
2144 else if (distPoint->CRLIssuer.cAltEntry)
2146 DWORD crlIssuerSize = bytesNeeded;
2148 strcpyW(str, issuer);
2149 str += strlenW(issuer);
2150 strcpyW(str, nameSep);
2151 str += strlenW(nameSep);
2152 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2153 &distPoint->CRLIssuer, str,
2156 str += crlIssuerSize / sizeof(WCHAR) - 1;
2166 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2167 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2168 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2171 CERT_ENHKEY_USAGE *usage;
2177 SetLastError(E_INVALIDARG);
2180 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2181 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2183 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2185 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2189 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2192 sepLen = strlenW(crlf) * sizeof(WCHAR);
2197 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2200 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
2201 sizeof(unknown) / sizeof(unknown[0]));
2202 for (i = 0; i < usage->cUsageIdentifier; i++)
2204 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2205 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2208 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
2210 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
2211 bytesNeeded += sizeof(WCHAR); /* space */
2212 bytesNeeded += sizeof(WCHAR); /* left paren */
2213 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
2215 bytesNeeded += sizeof(WCHAR); /* right paren */
2216 if (i < usage->cUsageIdentifier - 1)
2217 bytesNeeded += sepLen;
2220 *pcbFormat = bytesNeeded;
2221 else if (*pcbFormat < bytesNeeded)
2223 *pcbFormat = bytesNeeded;
2224 SetLastError(ERROR_MORE_DATA);
2229 LPWSTR str = pbFormat;
2231 *pcbFormat = bytesNeeded;
2232 for (i = 0; i < usage->cUsageIdentifier; i++)
2234 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2235 usage->rgpszUsageIdentifier[i],
2236 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2241 strcpyW(str, info->pwszName);
2242 str += strlenW(info->pwszName);
2246 strcpyW(str, unknown);
2247 str += strlenW(unknown);
2251 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2255 if (i < usage->cUsageIdentifier - 1)
2258 str += sepLen / sizeof(WCHAR);
2267 static struct BitToString netscapeCertTypeMap[] = {
2268 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2269 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2270 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2271 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2272 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2273 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2274 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2277 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2278 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2279 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2283 CRYPT_BIT_BLOB *bits;
2288 SetLastError(E_INVALIDARG);
2291 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2292 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2294 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2295 DWORD bytesNeeded = sizeof(WCHAR);
2297 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2298 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2299 if (!bits->cbData || bits->cbData > 1)
2301 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2303 *pcbFormat = bytesNeeded;
2304 else if (*pcbFormat < bytesNeeded)
2306 *pcbFormat = bytesNeeded;
2307 SetLastError(ERROR_MORE_DATA);
2312 LPWSTR str = pbFormat;
2314 *pcbFormat = bytesNeeded;
2315 strcpyW(str, infoNotAvailable);
2320 static BOOL stringsLoaded = FALSE;
2327 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2328 sizeof(netscapeCertTypeMap[0]); i++)
2329 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2330 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2331 stringsLoaded = TRUE;
2333 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2334 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2335 NULL, &bitStringLen, &first);
2336 bytesNeeded += bitStringLen;
2337 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2338 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2339 bits->cbData, NULL, &size);
2340 bytesNeeded += size;
2342 *pcbFormat = bytesNeeded;
2343 else if (*pcbFormat < bytesNeeded)
2345 *pcbFormat = bytesNeeded;
2346 SetLastError(ERROR_MORE_DATA);
2351 LPWSTR str = pbFormat;
2353 bitStringLen = bytesNeeded;
2355 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2356 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2357 str, &bitStringLen, &first);
2358 str += bitStringLen / sizeof(WCHAR) - 1;
2361 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2362 bits->cbData, str, &size);
2363 str += size / sizeof(WCHAR) - 1;
2373 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2374 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2375 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2376 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2377 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2378 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2380 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2381 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2382 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2385 SPC_FINANCIAL_CRITERIA criteria;
2386 DWORD size = sizeof(criteria);
2391 SetLastError(E_INVALIDARG);
2394 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2395 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2398 static BOOL stringsLoaded = FALSE;
2399 DWORD bytesNeeded = sizeof(WCHAR);
2405 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2406 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2407 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2408 sizeof(available) / sizeof(available[0]));
2409 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2410 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2411 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2412 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2413 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2414 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2415 stringsLoaded = TRUE;
2417 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2420 sepLen = strlenW(crlf) * sizeof(WCHAR);
2425 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2427 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2428 if (criteria.fFinancialInfoAvailable)
2430 bytesNeeded += strlenW(available) * sizeof(WCHAR);
2431 bytesNeeded += sepLen;
2432 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2433 if (criteria.fMeetsCriteria)
2434 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2436 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2439 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2441 *pcbFormat = bytesNeeded;
2442 else if (*pcbFormat < bytesNeeded)
2444 *pcbFormat = bytesNeeded;
2445 SetLastError(ERROR_MORE_DATA);
2450 LPWSTR str = pbFormat;
2452 *pcbFormat = bytesNeeded;
2453 strcpyW(str, financialCriteria);
2454 str += strlenW(financialCriteria);
2455 if (criteria.fFinancialInfoAvailable)
2457 strcpyW(str, available);
2458 str += strlenW(available);
2460 str += sepLen / sizeof(WCHAR);
2461 strcpyW(str, meetsCriteria);
2462 str += strlenW(meetsCriteria);
2463 if (criteria.fMeetsCriteria)
2470 strcpyW(str, notAvailable);
2471 str += strlenW(notAvailable);
2478 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2479 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2480 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2483 CERT_NAME_VALUE *value;
2489 SetLastError(E_INVALIDARG);
2492 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2493 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2496 *pcbFormat = value->Value.cbData;
2497 else if (*pcbFormat < value->Value.cbData)
2499 *pcbFormat = value->Value.cbData;
2500 SetLastError(ERROR_MORE_DATA);
2505 LPWSTR str = pbFormat;
2507 *pcbFormat = value->Value.cbData;
2508 strcpyW(str, (LPWSTR)value->Value.pbData);
2514 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2515 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2517 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2518 DWORD formatStrType, LPCSTR lpszStructType)
2520 CryptFormatObjectFunc format = NULL;
2522 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2524 SetLastError(ERROR_FILE_NOT_FOUND);
2527 if (IS_INTOID(lpszStructType))
2529 switch (LOWORD(lpszStructType))
2531 case LOWORD(X509_KEY_USAGE):
2532 format = CRYPT_FormatKeyUsage;
2534 case LOWORD(X509_ALTERNATE_NAME):
2535 format = CRYPT_FormatAltName;
2537 case LOWORD(X509_BASIC_CONSTRAINTS2):
2538 format = CRYPT_FormatBasicConstraints2;
2540 case LOWORD(X509_AUTHORITY_KEY_ID2):
2541 format = CRYPT_FormatAuthorityKeyId2;
2543 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2544 format = CRYPT_FormatAuthorityInfoAccess;
2546 case LOWORD(X509_CRL_DIST_POINTS):
2547 format = CRYPT_FormatCRLDistPoints;
2549 case LOWORD(X509_ENHANCED_KEY_USAGE):
2550 format = CRYPT_FormatEnhancedKeyUsage;
2552 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2553 format = CRYPT_FormatSpcFinancialCriteria;
2557 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2558 format = CRYPT_FormatAltName;
2559 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2560 format = CRYPT_FormatAltName;
2561 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2562 format = CRYPT_FormatKeyUsage;
2563 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2564 format = CRYPT_FormatAltName;
2565 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2566 format = CRYPT_FormatAltName;
2567 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2568 format = CRYPT_FormatBasicConstraints2;
2569 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2570 format = CRYPT_FormatAuthorityInfoAccess;
2571 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2572 format = CRYPT_FormatAuthorityKeyId2;
2573 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2574 format = CRYPT_FormatCRLDistPoints;
2575 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2576 format = CRYPT_FormatEnhancedKeyUsage;
2577 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2578 format = CRYPT_FormatNetscapeCertType;
2579 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2580 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2581 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2582 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2583 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2584 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2585 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2586 format = CRYPT_FormatUnicodeString;
2587 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2588 format = CRYPT_FormatSpcFinancialCriteria;
2592 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2593 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2594 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2596 CryptFormatObjectFunc format = NULL;
2597 HCRYPTOIDFUNCADDR hFunc = NULL;
2600 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2601 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2602 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2604 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2605 dwFormatStrType, lpszStructType)))
2607 static HCRYPTOIDFUNCSET set = NULL;
2610 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2611 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2612 (void **)&format, &hFunc);
2614 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2615 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2616 format = CRYPT_FormatHexString;
2618 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2619 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2622 CryptFreeOIDFunctionAddress(hFunc, 0);