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_QueryContextObject(DWORD dwObjectType, const void *pvObject,
65 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
66 DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
69 const CERT_BLOB *blob;
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);
83 case CERT_QUERY_OBJECT_BLOB:
84 blob = (const CERT_BLOB *)pvObject;
88 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
94 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
95 CERT_STORE_CREATE_NEW_FLAG, NULL);
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);
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);
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);
116 contentType = CERT_QUERY_CONTENT_CTL;
120 if (pdwMsgAndCertEncodingType)
121 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
123 *pdwContentType = contentType;
125 *phCertStore = CertDuplicateStore(store);
127 CertCloseStore(store, 0);
128 if (blob == &fileBlob)
129 CryptMemFree(blob->pbData);
130 TRACE("returning %d\n", 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)
140 const CERT_BLOB *blob;
141 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
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);
155 case CERT_QUERY_OBJECT_BLOB:
156 blob = (const CERT_BLOB *)pvObject;
160 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
166 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
167 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
170 DWORD contentType, certStoreOffset;
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);
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);
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);
212 SetLastError(ERROR_INVALID_DATA);
216 if (pdwMsgAndCertEncodingType)
217 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
219 *pdwContentType = contentType;
221 *phCertStore = CertDuplicateStore(
222 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
224 *ppvContext = contextInterface->duplicate(context);
228 if (contextInterface && context)
229 contextInterface->free(context);
230 if (blob == &fileBlob)
231 CryptMemFree(blob->pbData);
232 TRACE("returning %d\n", 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;
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? */
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);
261 if (pdwMsgAndCertEncodingType)
262 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
264 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
266 *phCertStore = CertDuplicateStore(store);
268 CertCloseStore(store, 0);
271 TRACE("returning %d\n", 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)
281 const CERT_BLOB *blob;
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
292 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
295 case CERT_QUERY_OBJECT_BLOB:
296 blob = (const CERT_BLOB *)pvObject;
300 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
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);
314 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
317 DWORD type, len = sizeof(type);
319 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
322 if ((dwExpectedContentTypeFlags &
323 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
325 if (type != CMSG_SIGNED)
327 SetLastError(ERROR_INVALID_DATA);
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);
341 else if (pdwContentType)
342 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
353 /* Failing that, try explicitly typed messages */
355 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
357 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
360 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
367 if (msg && pdwContentType)
368 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
371 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
373 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
376 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
383 if (msg && pdwContentType)
384 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
386 if (pdwMsgAndCertEncodingType)
387 *pdwMsgAndCertEncodingType = encodingType;
393 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
396 if (blob == &fileBlob)
397 CryptMemFree(blob->pbData);
398 TRACE("returning %d\n", ret);
402 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
403 const void *pvObject, DWORD dwExpectedContentTypeFlags,
404 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
405 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
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",
417 SetLastError(E_INVALIDARG);
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);
427 SIP_DISPATCH_INFO sip;
429 memset(&sip, 0, sizeof(sip));
430 sip.cbSize = sizeof(sip);
431 ret = CryptSIPLoad(&subject, 0, &sip);
434 SIP_SUBJECTINFO subjectInfo;
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,
447 blob.pbData = CryptMemAlloc(blob.cbData);
450 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
451 &blob.cbData, blob.pbData);
454 ret = CRYPT_QueryMessageObject(
455 CERT_QUERY_OBJECT_BLOB, &blob,
456 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
457 pdwMsgAndCertEncodingType, NULL, phCertStore,
459 if (ret && pdwContentType)
461 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
463 CryptMemFree(blob.pbData);
467 SetLastError(ERROR_OUTOFMEMORY);
475 TRACE("returning %d\n", 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;
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);
505 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
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);
524 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
526 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
527 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
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);
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,
547 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
549 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
550 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
553 TRACE("returning %d\n", 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,
566 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
568 bytesNeeded = sizeof(WCHAR);
571 *pcbFormat = bytesNeeded;
574 else if (*pcbFormat < bytesNeeded)
576 *pcbFormat = bytesNeeded;
577 SetLastError(ERROR_MORE_DATA);
582 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
583 static const WCHAR endFmt[] = { '%','0','2','x',0 };
585 LPWSTR ptr = pbFormat;
587 *pcbFormat = bytesNeeded;
590 for (i = 0; i < cbEncoded; i++)
592 if (i < cbEncoded - 1)
593 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
595 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
605 #define MAX_STRING_RESOURCE_LEN 128
607 static const WCHAR crlf[] = { '\r','\n',0 };
608 static const WCHAR commaSpace[] = { ',',' ',0 };
610 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
611 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
612 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
613 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
615 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
616 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
617 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
621 CERT_BASIC_CONSTRAINTS2_INFO *info;
626 SetLastError(E_INVALIDARG);
629 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
630 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
632 static const WCHAR pathFmt[] = { '%','d',0 };
633 static BOOL stringsLoaded = FALSE;
634 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
635 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
636 LPCWSTR sep, subjectType;
639 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
642 sepLen = strlenW(crlf) * sizeof(WCHAR);
647 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
652 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
653 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
654 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
655 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
656 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
658 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
659 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
660 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
661 stringsLoaded = TRUE;
663 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
665 subjectType = subjectTypeCA;
667 subjectType = subjectTypeEndCert;
668 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
669 bytesNeeded += sepLen;
670 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
671 if (info->fPathLenConstraint)
672 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
674 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
675 sizeof(pathLength) / sizeof(pathLength[0]));
676 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
678 *pcbFormat = bytesNeeded;
679 else if (*pcbFormat < bytesNeeded)
681 *pcbFormat = bytesNeeded;
682 SetLastError(ERROR_MORE_DATA);
687 LPWSTR str = pbFormat;
689 *pcbFormat = bytesNeeded;
690 strcpyW(str, subjectTypeHeader);
691 str += strlenW(subjectTypeHeader);
692 strcpyW(str, subjectType);
693 str += strlenW(subjectType);
695 str += sepLen / sizeof(WCHAR);
696 strcpyW(str, pathLengthHeader);
697 str += strlenW(pathLengthHeader);
698 strcpyW(str, pathLength);
699 str += strlenW(pathLength);
706 static BOOL CRYPT_FormatHexStringWithPrefix(CRYPT_DATA_BLOB *blob, int id,
707 LPWSTR str, DWORD *pcbStr)
709 WCHAR buf[MAX_STRING_RESOURCE_LEN];
713 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
714 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
715 blob->pbData, blob->cbData, NULL, &bytesNeeded);
716 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
719 *pcbStr = bytesNeeded;
722 else if (*pcbStr < bytesNeeded)
724 *pcbStr = bytesNeeded;
725 SetLastError(ERROR_MORE_DATA);
730 *pcbStr = bytesNeeded;
733 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
734 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
735 blob->pbData, blob->cbData, str, &bytesNeeded);
740 static BOOL CRYPT_FormatKeyId(CRYPT_DATA_BLOB *keyId, LPWSTR str,
743 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
746 static BOOL CRYPT_FormatCertSerialNumber(CRYPT_DATA_BLOB *serialNum, LPWSTR str,
749 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
753 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
755 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
756 CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
759 WCHAR buf[MAX_STRING_RESOURCE_LEN];
760 WCHAR mask[MAX_STRING_RESOURCE_LEN];
763 DWORD bytesNeeded = sizeof(WCHAR);
765 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
766 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
767 switch (entry->dwAltNameChoice)
769 case CERT_ALT_NAME_RFC822_NAME:
770 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
771 sizeof(buf) / sizeof(buf[0]));
772 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
775 case CERT_ALT_NAME_DNS_NAME:
776 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
777 sizeof(buf) / sizeof(buf[0]));
778 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
781 case CERT_ALT_NAME_DIRECTORY_NAME:
783 DWORD strType = dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE
784 ? CERT_NAME_STR_CRLF_FLAG : 0;
785 DWORD directoryNameLen = CertNameToStrW(X509_ASN_ENCODING,
786 &entry->u.DirectoryName, strType, NULL, 0);
788 LoadStringW(hInstance, IDS_ALT_NAME_OTHER_NAME, buf,
789 sizeof(buf) / sizeof(buf[0]));
790 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
794 case CERT_ALT_NAME_URL:
795 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
796 sizeof(buf) / sizeof(buf[0]));
797 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
800 case CERT_ALT_NAME_IP_ADDRESS:
802 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
803 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
805 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
808 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
809 sizeof(buf) / sizeof(buf[0]));
810 if (entry->u.IPAddress.cbData == 8)
812 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
814 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
815 sizeof(mask) / sizeof(mask[0]));
816 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
817 sprintfW(ipAddrBuf, ipAddrFmt,
818 entry->u.IPAddress.pbData[0],
819 entry->u.IPAddress.pbData[1],
820 entry->u.IPAddress.pbData[2],
821 entry->u.IPAddress.pbData[3]);
822 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
823 /* indent again, for the mask line */
824 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
825 sprintfW(maskBuf, ipAddrFmt,
826 entry->u.IPAddress.pbData[4],
827 entry->u.IPAddress.pbData[5],
828 entry->u.IPAddress.pbData[6],
829 entry->u.IPAddress.pbData[7]);
830 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
831 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
835 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
836 entry->u.IPAddress.pbData[0],
837 entry->u.IPAddress.pbData[1],
838 entry->u.IPAddress.pbData[2],
839 entry->u.IPAddress.pbData[3],
840 entry->u.IPAddress.pbData[4],
841 entry->u.IPAddress.pbData[5],
842 entry->u.IPAddress.pbData[6],
843 entry->u.IPAddress.pbData[7]);
844 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
850 FIXME("unknown IP address format (%d bytes)\n",
851 entry->u.IPAddress.cbData);
857 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
862 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
864 *pcbStr = bytesNeeded;
865 else if (*pcbStr < bytesNeeded)
867 *pcbStr = bytesNeeded;
868 SetLastError(ERROR_MORE_DATA);
875 *pcbStr = bytesNeeded;
876 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
878 for (i = 0; i < indentLevel; i++)
880 strcpyW(str, indent);
881 str += strlenW(indent);
886 switch (entry->dwAltNameChoice)
888 case CERT_ALT_NAME_RFC822_NAME:
889 case CERT_ALT_NAME_DNS_NAME:
890 case CERT_ALT_NAME_URL:
891 strcpyW(str, entry->u.pwszURL);
893 case CERT_ALT_NAME_DIRECTORY_NAME:
895 DWORD strType = dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE
896 ? CERT_NAME_STR_CRLF_FLAG : 0;
898 CertNameToStrW(X509_ASN_ENCODING, &entry->u.DirectoryName,
899 strType, str, bytesNeeded / sizeof(WCHAR));
902 case CERT_ALT_NAME_IP_ADDRESS:
903 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
905 strcpyW(str, ipAddrBuf);
906 str += strlenW(ipAddrBuf);
908 str += strlenW(crlf);
909 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
911 for (i = 0; i < indentLevel; i++)
913 strcpyW(str, indent);
914 str += strlenW(indent);
918 str += strlenW(mask);
919 strcpyW(str, maskBuf);
922 strcpyW(str, ipAddrBuf);
930 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
931 CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
933 DWORD i, size, bytesNeeded = 0;
938 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
941 sepLen = strlenW(crlf) * sizeof(WCHAR);
946 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
949 for (i = 0; ret && i < name->cAltEntry; i++)
951 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
952 &name->rgAltEntry[i], NULL, &size);
955 bytesNeeded += size - sizeof(WCHAR);
956 if (i < name->cAltEntry - 1)
957 bytesNeeded += sepLen;
962 bytesNeeded += sizeof(WCHAR);
964 *pcbStr = bytesNeeded;
965 else if (*pcbStr < bytesNeeded)
967 *pcbStr = bytesNeeded;
968 SetLastError(ERROR_MORE_DATA);
973 *pcbStr = bytesNeeded;
974 for (i = 0; ret && i < name->cAltEntry; i++)
976 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
977 &name->rgAltEntry[i], str, &size);
980 str += size / sizeof(WCHAR) - 1;
981 if (i < name->cAltEntry - 1)
984 str += sepLen / sizeof(WCHAR);
993 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
994 CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
996 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1000 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1001 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, issuer, NULL,
1003 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1007 *pcbStr = bytesNeeded;
1008 else if (*pcbStr < bytesNeeded)
1010 *pcbStr = bytesNeeded;
1011 SetLastError(ERROR_MORE_DATA);
1016 *pcbStr = bytesNeeded;
1018 str += strlenW(str);
1019 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1020 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, issuer, str,
1027 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1028 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1029 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1032 CERT_AUTHORITY_KEY_ID2_INFO *info;
1038 SetLastError(E_INVALIDARG);
1041 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1042 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1044 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1047 BOOL needSeparator = FALSE;
1049 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1052 sepLen = strlenW(crlf) * sizeof(WCHAR);
1057 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1060 if (info->KeyId.cbData)
1062 needSeparator = TRUE;
1063 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1066 /* don't include NULL-terminator more than once */
1067 bytesNeeded += size - sizeof(WCHAR);
1070 if (info->AuthorityCertIssuer.cAltEntry)
1073 bytesNeeded += sepLen;
1074 needSeparator = TRUE;
1075 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1076 &info->AuthorityCertIssuer, NULL, &size);
1079 /* don't include NULL-terminator more than once */
1080 bytesNeeded += size - sizeof(WCHAR);
1083 if (info->AuthorityCertSerialNumber.cbData)
1086 bytesNeeded += sepLen;
1087 ret = CRYPT_FormatCertSerialNumber(
1088 &info->AuthorityCertSerialNumber, NULL, &size);
1091 /* don't include NULL-terminator more than once */
1092 bytesNeeded += size - sizeof(WCHAR);
1098 *pcbFormat = bytesNeeded;
1099 else if (*pcbFormat < bytesNeeded)
1101 *pcbFormat = bytesNeeded;
1102 SetLastError(ERROR_MORE_DATA);
1107 LPWSTR str = pbFormat;
1109 *pcbFormat = bytesNeeded;
1110 needSeparator = FALSE;
1111 if (info->KeyId.cbData)
1113 needSeparator = TRUE;
1114 /* Overestimate size available, it's already been checked
1118 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1120 str += size / sizeof(WCHAR) - 1;
1122 if (info->AuthorityCertIssuer.cAltEntry)
1127 str += sepLen / sizeof(WCHAR);
1129 needSeparator = TRUE;
1130 /* Overestimate size available, it's already been checked
1134 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1135 &info->AuthorityCertIssuer, str, &size);
1137 str += size / sizeof(WCHAR) - 1;
1139 if (info->AuthorityCertSerialNumber.cbData)
1144 str += sepLen / sizeof(WCHAR);
1146 /* Overestimate size available, it's already been checked
1150 ret = CRYPT_FormatCertSerialNumber(
1151 &info->AuthorityCertSerialNumber, str, &size);
1160 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
1162 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1163 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1164 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1165 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1166 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1167 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1168 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1170 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1171 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1174 CERT_AUTHORITY_INFO_ACCESS *info;
1180 SetLastError(E_INVALIDARG);
1183 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1184 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1185 NULL, &info, &size)))
1187 DWORD bytesNeeded = sizeof(WCHAR);
1189 if (!info->cAccDescr)
1191 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1193 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1194 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1195 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1197 *pcbFormat = bytesNeeded;
1198 else if (*pcbFormat < bytesNeeded)
1200 *pcbFormat = bytesNeeded;
1201 SetLastError(ERROR_MORE_DATA);
1206 *pcbFormat = bytesNeeded;
1207 strcpyW((LPWSTR)pbFormat, infoNotAvailable);
1212 static const WCHAR colonSep[] = { ':',' ',0 };
1213 static const WCHAR numFmt[] = { '%','d',0 };
1214 static const WCHAR equal[] = { '=',0 };
1215 static BOOL stringsLoaded = FALSE;
1217 LPCWSTR headingSep, accessMethodSep, locationSep;
1218 WCHAR accessDescrNum[11];
1222 LoadStringW(hInstance, IDS_AIA, aia,
1223 sizeof(aia) / sizeof(aia[0]));
1224 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1225 sizeof(accessMethod) / sizeof(accessMethod[0]));
1226 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1227 sizeof(ocsp) / sizeof(ocsp[0]));
1228 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1229 sizeof(caIssuers) / sizeof(caIssuers[0]));
1230 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1231 sizeof(unknown) / sizeof(unknown[0]));
1232 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1233 sizeof(accessLocation) / sizeof(accessLocation[0]));
1234 stringsLoaded = TRUE;
1236 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1239 accessMethodSep = crlf;
1240 locationSep = colonCrlf;
1244 headingSep = colonSep;
1245 accessMethodSep = commaSpace;
1246 locationSep = equal;
1249 for (i = 0; ret && i < info->cAccDescr; i++)
1252 bytesNeeded += sizeof(WCHAR); /* left bracket */
1253 sprintfW(accessDescrNum, numFmt, i + 1);
1254 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1255 bytesNeeded += sizeof(WCHAR); /* right bracket */
1256 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1257 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1259 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1260 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1261 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1262 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1264 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1265 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1266 szOID_PKIX_CA_ISSUERS))
1267 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1269 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1270 bytesNeeded += sizeof(WCHAR); /* space */
1271 bytesNeeded += sizeof(WCHAR); /* left paren */
1272 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1274 bytesNeeded += sizeof(WCHAR); /* right paren */
1275 /* Delimiter between access method and location */
1276 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1277 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1278 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1279 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1280 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1281 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1282 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1284 bytesNeeded += size - sizeof(WCHAR);
1285 /* Need extra delimiter between access method entries */
1286 if (i < info->cAccDescr - 1)
1287 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1292 *pcbFormat = bytesNeeded;
1293 else if (*pcbFormat < bytesNeeded)
1295 *pcbFormat = bytesNeeded;
1296 SetLastError(ERROR_MORE_DATA);
1301 LPWSTR str = pbFormat;
1302 DWORD altNameEntrySize;
1304 *pcbFormat = bytesNeeded;
1305 for (i = 0; ret && i < info->cAccDescr; i++)
1310 sprintfW(accessDescrNum, numFmt, i + 1);
1311 strcpyW(str, accessDescrNum);
1312 str += strlenW(accessDescrNum);
1315 str += strlenW(aia);
1316 strcpyW(str, headingSep);
1317 str += strlenW(headingSep);
1318 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1320 strcpyW(str, indent);
1321 str += strlenW(indent);
1323 strcpyW(str, accessMethod);
1324 str += strlenW(accessMethod);
1325 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1329 str += strlenW(ocsp);
1331 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1332 szOID_PKIX_CA_ISSUERS))
1334 strcpyW(str, caIssuers);
1335 str += strlenW(caIssuers);
1339 strcpyW(str, unknown);
1340 str += strlenW(unknown);
1344 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1345 *oidPtr; oidPtr++, str++)
1348 strcpyW(str, accessMethodSep);
1349 str += strlenW(accessMethodSep);
1350 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1352 strcpyW(str, indent);
1353 str += strlenW(indent);
1355 strcpyW(str, accessLocation);
1356 str += strlenW(accessLocation);
1357 strcpyW(str, locationSep);
1358 str += strlenW(locationSep);
1359 /* This overestimates the size available, but that
1360 * won't matter since we checked earlier whether enough
1361 * space for the entire string was available.
1363 altNameEntrySize = bytesNeeded;
1364 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1365 &info->rgAccDescr[i].AccessLocation, str,
1368 str += altNameEntrySize / sizeof(WCHAR) - 1;
1369 if (i < info->cAccDescr - 1)
1371 strcpyW(str, accessMethodSep);
1372 str += strlenW(accessMethodSep);
1383 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1384 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1385 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1386 static WCHAR superceded[MAX_STRING_RESOURCE_LEN];
1387 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1388 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1390 struct reason_map_entry
1396 static struct reason_map_entry reason_map[] = {
1397 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1398 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1399 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1400 IDS_REASON_AFFILIATION_CHANGED },
1401 { CRL_REASON_SUPERSEDED_FLAG, superceded, IDS_REASON_SUPERCEDED },
1402 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1403 IDS_REASON_CESSATION_OF_OPERATION },
1404 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1405 IDS_REASON_CERTIFICATE_HOLD },
1408 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1409 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1411 static const WCHAR sep[] = { ',',' ',0 };
1412 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1413 static BOOL stringsLoaded = FALSE;
1414 int i, numReasons = 0;
1416 DWORD bytesNeeded = sizeof(WCHAR);
1421 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1422 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1423 MAX_STRING_RESOURCE_LEN);
1424 stringsLoaded = TRUE;
1426 /* No need to check reasonFlags->cbData, we already know it's positive.
1427 * Ignore any other bytes, as they're for undefined bits.
1429 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1431 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1433 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1435 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1438 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1439 bytesNeeded += strlenW(bits);
1441 *pcbStr = bytesNeeded;
1442 else if (*pcbStr < bytesNeeded)
1444 *pcbStr = bytesNeeded;
1445 SetLastError(ERROR_MORE_DATA);
1450 *pcbStr = bytesNeeded;
1451 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1453 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1455 strcpyW(str, reason_map[i].reason);
1456 str += strlenW(reason_map[i].reason);
1457 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1461 str += strlenW(sep);
1470 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1471 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1472 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1473 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1474 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1475 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1477 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1478 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1479 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1482 CRL_DIST_POINTS_INFO *info;
1488 SetLastError(E_INVALIDARG);
1491 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1492 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1494 static const WCHAR numFmt[] = { '%','d',0 };
1495 static const WCHAR colonSep[] = { ':',' ',0 };
1496 static const WCHAR commaSep[] = { ',',' ',0 };
1497 static const WCHAR colon[] = { ':',0 };
1498 static BOOL stringsLoaded = FALSE;
1499 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1500 BOOL haveAnEntry = FALSE;
1501 LPCWSTR headingSep, distPointSep, nameSep;
1502 WCHAR distPointNum[11];
1507 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1508 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1509 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1510 sizeof(distPointName) / sizeof(distPointName[0]));
1511 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1512 sizeof(fullName) / sizeof(fullName[0]));
1513 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1514 sizeof(rdnName) / sizeof(rdnName[0]));
1515 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1516 sizeof(reason) / sizeof(reason[0]));
1517 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1518 sizeof(issuer) / sizeof(issuer[0]));
1519 stringsLoaded = TRUE;
1521 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1524 distPointSep = crlf;
1525 nameSep = colonCrlf;
1529 headingSep = colonSep;
1530 distPointSep = commaSep;
1534 for (i = 0; ret && i < info->cDistPoint; i++)
1536 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1538 if (distPoint->DistPointName.dwDistPointNameChoice !=
1539 CRL_DIST_POINT_NO_NAME)
1541 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1542 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1543 if (distPoint->DistPointName.dwDistPointNameChoice ==
1544 CRL_DIST_POINT_FULL_NAME)
1545 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
1547 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
1548 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1549 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1550 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
1551 /* The indent level (3) is higher than when used as the issuer,
1552 * because the name is subordinate to the name type (full vs.
1555 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
1556 &distPoint->DistPointName.u.FullName, NULL, &size);
1558 bytesNeeded += size - sizeof(WCHAR);
1561 else if (distPoint->ReasonFlags.cbData)
1563 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
1564 ret = CRYPT_FormatReason(dwFormatStrType,
1565 &distPoint->ReasonFlags, NULL, &size);
1567 bytesNeeded += size - sizeof(WCHAR);
1570 else if (distPoint->CRLIssuer.cAltEntry)
1572 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
1573 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1574 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
1575 &distPoint->CRLIssuer, NULL, &size);
1577 bytesNeeded += size - sizeof(WCHAR);
1582 bytesNeeded += sizeof(WCHAR); /* left bracket */
1583 sprintfW(distPointNum, numFmt, i + 1);
1584 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
1585 bytesNeeded += sizeof(WCHAR); /* right bracket */
1586 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
1587 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1588 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1589 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1594 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1596 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1597 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1598 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1600 *pcbFormat = bytesNeeded;
1601 else if (*pcbFormat < bytesNeeded)
1603 *pcbFormat = bytesNeeded;
1604 SetLastError(ERROR_MORE_DATA);
1609 *pcbFormat = bytesNeeded;
1610 strcpyW((LPWSTR)pbFormat, infoNotAvailable);
1616 *pcbFormat = bytesNeeded;
1617 else if (*pcbFormat < bytesNeeded)
1619 *pcbFormat = bytesNeeded;
1620 SetLastError(ERROR_MORE_DATA);
1625 LPWSTR str = pbFormat;
1627 *pcbFormat = bytesNeeded;
1628 for (i = 0; ret && i < info->cDistPoint; i++)
1630 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1633 sprintfW(distPointNum, numFmt, i + 1);
1634 strcpyW(str, distPointNum);
1635 str += strlenW(distPointNum);
1637 strcpyW(str, crlDistPoint);
1638 str += strlenW(crlDistPoint);
1639 strcpyW(str, headingSep);
1640 str += strlenW(headingSep);
1641 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1643 strcpyW(str, indent);
1644 str += strlenW(indent);
1646 if (distPoint->DistPointName.dwDistPointNameChoice !=
1647 CRL_DIST_POINT_NO_NAME)
1649 DWORD altNameSize = bytesNeeded;
1651 strcpyW(str, distPointName);
1652 str += strlenW(distPointName);
1653 strcpyW(str, nameSep);
1654 str += strlenW(nameSep);
1655 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1657 strcpyW(str, indent);
1658 str += strlenW(indent);
1659 strcpyW(str, indent);
1660 str += strlenW(indent);
1662 if (distPoint->DistPointName.dwDistPointNameChoice ==
1663 CRL_DIST_POINT_FULL_NAME)
1665 strcpyW(str, fullName);
1666 str += strlenW(fullName);
1670 strcpyW(str, rdnName);
1671 str += strlenW(rdnName);
1673 strcpyW(str, nameSep);
1674 str += strlenW(nameSep);
1675 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
1676 &distPoint->DistPointName.u.FullName, str,
1679 str += altNameSize / sizeof(WCHAR) - 1;
1681 else if (distPoint->ReasonFlags.cbData)
1683 DWORD reasonSize = bytesNeeded;
1685 strcpyW(str, reason);
1686 str += strlenW(reason);
1687 ret = CRYPT_FormatReason(dwFormatStrType,
1688 &distPoint->ReasonFlags, str, &reasonSize);
1690 str += reasonSize / sizeof(WCHAR) - 1;
1692 else if (distPoint->CRLIssuer.cAltEntry)
1694 DWORD crlIssuerSize = bytesNeeded;
1696 strcpyW(str, issuer);
1697 str += strlenW(issuer);
1698 strcpyW(str, nameSep);
1699 str += strlenW(nameSep);
1700 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
1701 &distPoint->CRLIssuer, str,
1704 str += crlIssuerSize / sizeof(WCHAR) - 1;
1714 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
1715 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1716 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1719 CERT_ENHKEY_USAGE *usage;
1725 SetLastError(E_INVALIDARG);
1728 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
1729 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
1731 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1733 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1737 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1740 sepLen = strlenW(crlf) * sizeof(WCHAR);
1745 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1748 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
1749 sizeof(unknown) / sizeof(unknown[0]));
1750 for (i = 0; i < usage->cUsageIdentifier; i++)
1752 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1753 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1756 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
1758 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1759 bytesNeeded += sizeof(WCHAR); /* space */
1760 bytesNeeded += sizeof(WCHAR); /* left paren */
1761 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
1763 bytesNeeded += sizeof(WCHAR); /* right paren */
1764 if (i < usage->cUsageIdentifier - 1)
1765 bytesNeeded += sepLen;
1768 *pcbFormat = bytesNeeded;
1769 else if (*pcbFormat < bytesNeeded)
1771 *pcbFormat = bytesNeeded;
1772 SetLastError(ERROR_MORE_DATA);
1777 LPWSTR str = pbFormat;
1779 *pcbFormat = bytesNeeded;
1780 for (i = 0; i < usage->cUsageIdentifier; i++)
1782 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1783 usage->rgpszUsageIdentifier[i],
1784 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1789 strcpyW(str, info->pwszName);
1790 str += strlenW(info->pwszName);
1794 strcpyW(str, unknown);
1795 str += strlenW(unknown);
1799 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
1803 if (i < usage->cUsageIdentifier - 1)
1806 str += sepLen / sizeof(WCHAR);
1815 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
1816 static WCHAR available[MAX_STRING_RESOURCE_LEN];
1817 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
1818 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
1819 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
1820 static WCHAR no[MAX_STRING_RESOURCE_LEN];
1822 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
1823 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1824 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1827 SPC_FINANCIAL_CRITERIA criteria;
1828 DWORD size = sizeof(criteria);
1833 SetLastError(E_INVALIDARG);
1836 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1837 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
1840 static BOOL stringsLoaded = FALSE;
1841 DWORD bytesNeeded = sizeof(WCHAR);
1847 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
1848 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
1849 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
1850 sizeof(available) / sizeof(available[0]));
1851 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
1852 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
1853 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
1854 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
1855 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
1856 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
1857 stringsLoaded = TRUE;
1859 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1862 sepLen = strlenW(crlf) * sizeof(WCHAR);
1867 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1869 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
1870 if (criteria.fFinancialInfoAvailable)
1872 bytesNeeded += strlenW(available) * sizeof(WCHAR);
1873 bytesNeeded += sepLen;
1874 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
1875 if (criteria.fMeetsCriteria)
1876 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
1878 bytesNeeded += strlenW(no) * sizeof(WCHAR);
1881 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
1883 *pcbFormat = bytesNeeded;
1884 else if (*pcbFormat < bytesNeeded)
1886 *pcbFormat = bytesNeeded;
1887 SetLastError(ERROR_MORE_DATA);
1892 LPWSTR str = pbFormat;
1894 *pcbFormat = bytesNeeded;
1895 strcpyW(str, financialCriteria);
1896 str += strlenW(financialCriteria);
1897 if (criteria.fFinancialInfoAvailable)
1899 strcpyW(str, available);
1900 str += strlenW(available);
1902 str += sepLen / sizeof(WCHAR);
1903 strcpyW(str, meetsCriteria);
1904 str += strlenW(meetsCriteria);
1905 if (criteria.fMeetsCriteria)
1912 strcpyW(str, notAvailable);
1913 str += strlenW(notAvailable);
1920 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
1921 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
1923 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
1924 DWORD formatStrType, LPCSTR lpszStructType)
1926 CryptFormatObjectFunc format = NULL;
1928 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
1930 SetLastError(ERROR_FILE_NOT_FOUND);
1933 if (!HIWORD(lpszStructType))
1935 switch (LOWORD(lpszStructType))
1937 case LOWORD(X509_BASIC_CONSTRAINTS2):
1938 format = CRYPT_FormatBasicConstraints2;
1940 case LOWORD(X509_AUTHORITY_KEY_ID2):
1941 format = CRYPT_FormatAuthorityKeyId2;
1943 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
1944 format = CRYPT_FormatAuthorityInfoAccess;
1946 case LOWORD(X509_CRL_DIST_POINTS):
1947 format = CRYPT_FormatCRLDistPoints;
1949 case LOWORD(X509_ENHANCED_KEY_USAGE):
1950 format = CRYPT_FormatEnhancedKeyUsage;
1952 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
1953 format = CRYPT_FormatSpcFinancialCriteria;
1957 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
1958 format = CRYPT_FormatBasicConstraints2;
1959 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
1960 format = CRYPT_FormatAuthorityInfoAccess;
1961 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
1962 format = CRYPT_FormatAuthorityKeyId2;
1963 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
1964 format = CRYPT_FormatCRLDistPoints;
1965 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
1966 format = CRYPT_FormatEnhancedKeyUsage;
1967 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
1968 format = CRYPT_FormatSpcFinancialCriteria;
1969 if (!format && !(formatStrType & CRYPT_FORMAT_STR_NO_HEX))
1970 format = CRYPT_FormatHexString;
1974 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
1975 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
1976 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
1978 CryptFormatObjectFunc format = NULL;
1979 HCRYPTOIDFUNCADDR hFunc = NULL;
1982 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
1983 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
1984 pbEncoded, cbEncoded, pbFormat, pcbFormat);
1986 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
1987 dwFormatStrType, lpszStructType)))
1989 static HCRYPTOIDFUNCSET set = NULL;
1992 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
1993 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
1994 (void **)&format, &hFunc);
1997 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
1998 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2001 CryptFreeOIDFunctionAddress(hFunc, 0);