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
27 #include "crypt32_private.h"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
34 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
39 TRACE("%s\n", debugstr_w(fileName));
41 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
42 OPEN_EXISTING, 0, NULL);
43 if (file != INVALID_HANDLE_VALUE)
46 blob->cbData = GetFileSize(file, NULL);
49 blob->pbData = CryptMemAlloc(blob->cbData);
54 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
59 TRACE("returning %d\n", ret);
63 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
64 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
65 DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
68 const CERT_BLOB *blob;
75 case CERT_QUERY_OBJECT_FILE:
76 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
77 * just read the file directly
79 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
82 case CERT_QUERY_OBJECT_BLOB:
83 blob = (const CERT_BLOB *)pvObject;
87 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
93 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
94 CERT_STORE_CREATE_NEW_FLAG, NULL);
96 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
98 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
99 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
101 contentType = CERT_QUERY_CONTENT_CERT;
103 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
105 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
106 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
108 contentType = CERT_QUERY_CONTENT_CRL;
110 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
112 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
113 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
115 contentType = CERT_QUERY_CONTENT_CTL;
119 if (pdwMsgAndCertEncodingType)
120 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
122 *pdwContentType = contentType;
124 *phCertStore = CertDuplicateStore(store);
126 CertCloseStore(store, 0);
127 if (blob == &fileBlob)
128 CryptMemFree(blob->pbData);
129 TRACE("returning %d\n", ret);
133 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
134 const void *pvObject, DWORD dwExpectedContentTypeFlags,
135 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
136 HCERTSTORE *phCertStore, const void **ppvContext)
139 const CERT_BLOB *blob;
140 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
145 switch (dwObjectType)
147 case CERT_QUERY_OBJECT_FILE:
148 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
149 * just read the file directly
151 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
154 case CERT_QUERY_OBJECT_BLOB:
155 blob = (const CERT_BLOB *)pvObject;
159 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
165 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
166 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
169 DWORD contentType, certStoreOffset;
174 case CERT_STORE_CERTIFICATE_CONTEXT:
175 contextInterface = pCertInterface;
176 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
177 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
178 if (!(dwExpectedContentTypeFlags &
179 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
181 SetLastError(ERROR_INVALID_DATA);
186 case CERT_STORE_CRL_CONTEXT:
187 contextInterface = pCRLInterface;
188 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
189 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
190 if (!(dwExpectedContentTypeFlags &
191 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
193 SetLastError(ERROR_INVALID_DATA);
198 case CERT_STORE_CTL_CONTEXT:
199 contextInterface = pCTLInterface;
200 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
201 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
202 if (!(dwExpectedContentTypeFlags &
203 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
205 SetLastError(ERROR_INVALID_DATA);
211 SetLastError(ERROR_INVALID_DATA);
215 if (pdwMsgAndCertEncodingType)
216 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
218 *pdwContentType = contentType;
220 *phCertStore = CertDuplicateStore(
221 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
223 *ppvContext = contextInterface->duplicate(context);
227 if (contextInterface && context)
228 contextInterface->free(context);
229 if (blob == &fileBlob)
230 CryptMemFree(blob->pbData);
231 TRACE("returning %d\n", ret);
235 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
236 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
237 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
239 LPCWSTR fileName = (LPCWSTR)pvObject;
243 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
245 FIXME("unimplemented for non-file type %d\n", dwObjectType);
246 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
249 TRACE("%s\n", debugstr_w(fileName));
250 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
251 OPEN_EXISTING, 0, NULL);
252 if (file != INVALID_HANDLE_VALUE)
254 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
255 CERT_STORE_CREATE_NEW_FLAG, NULL);
257 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
260 if (pdwMsgAndCertEncodingType)
261 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
263 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
265 *phCertStore = CertDuplicateStore(store);
267 CertCloseStore(store, 0);
270 TRACE("returning %d\n", ret);
274 /* Used to decode non-embedded messages */
275 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
276 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
277 DWORD *pdwContentType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
280 const CERT_BLOB *blob;
282 HCRYPTMSG msg = NULL;
283 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
285 switch (dwObjectType)
287 case CERT_QUERY_OBJECT_FILE:
288 /* This isn't an embedded PKCS7 message, so just read the file
291 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
294 case CERT_QUERY_OBJECT_BLOB:
295 blob = (const CERT_BLOB *)pvObject;
299 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
306 /* Try it first as a PKCS content info */
307 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
308 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
310 msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL);
313 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
316 DWORD type, len = sizeof(type);
318 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
321 if ((dwExpectedContentTypeFlags &
322 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
324 if (type != CMSG_SIGNED)
326 SetLastError(ERROR_INVALID_DATA);
329 else if (pdwContentType)
330 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
332 else if ((dwExpectedContentTypeFlags &
333 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
335 if (type != CMSG_DATA)
337 SetLastError(ERROR_INVALID_DATA);
340 else if (pdwContentType)
341 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
352 /* Failing that, try explicitly typed messages */
354 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
356 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
359 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
366 if (msg && pdwContentType)
367 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
370 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
372 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
375 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
382 if (msg && pdwContentType)
383 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
385 if (pdwMsgAndCertEncodingType)
386 *pdwMsgAndCertEncodingType = encodingType;
392 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
395 if (blob == &fileBlob)
396 CryptMemFree(blob->pbData);
397 TRACE("returning %d\n", ret);
401 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
402 const void *pvObject, DWORD dwExpectedContentTypeFlags,
403 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
404 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
410 TRACE("%s\n", debugstr_w((LPCWSTR)pvObject));
412 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
414 FIXME("don't know what to do for type %d embedded signed messages\n",
416 SetLastError(E_INVALIDARG);
419 file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ,
420 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
421 if (file != INVALID_HANDLE_VALUE)
423 ret = CryptSIPRetrieveSubjectGuid((LPCWSTR)pvObject, file, &subject);
426 SIP_DISPATCH_INFO sip;
428 memset(&sip, 0, sizeof(sip));
429 sip.cbSize = sizeof(sip);
430 ret = CryptSIPLoad(&subject, 0, &sip);
433 SIP_SUBJECTINFO subjectInfo;
437 memset(&subjectInfo, 0, sizeof(subjectInfo));
438 subjectInfo.cbSize = sizeof(subjectInfo);
439 subjectInfo.pgSubjectType = &subject;
440 subjectInfo.hFile = file;
441 subjectInfo.pwsFileName = (LPCWSTR)pvObject;
442 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
446 blob.pbData = CryptMemAlloc(blob.cbData);
449 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
450 &blob.cbData, blob.pbData);
453 ret = CRYPT_QueryMessageObject(
454 CERT_QUERY_OBJECT_BLOB, &blob,
455 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
456 pdwMsgAndCertEncodingType, NULL, phCertStore,
458 if (ret && pdwContentType)
460 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
462 CryptMemFree(blob.pbData);
466 SetLastError(ERROR_OUTOFMEMORY);
474 TRACE("returning %d\n", ret);
478 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
479 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
480 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
481 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
482 const void **ppvContext)
484 static const DWORD unimplementedTypes =
485 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
486 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
489 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
490 dwObjectType, pvObject, dwExpectedContentTypeFlags,
491 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
492 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
494 if (dwExpectedContentTypeFlags & unimplementedTypes)
495 WARN("unimplemented for types %08x\n",
496 dwExpectedContentTypeFlags & unimplementedTypes);
497 if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY))
499 FIXME("unimplemented for anything but binary\n");
500 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
504 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
514 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
515 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
516 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
518 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
519 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
520 phCertStore, ppvContext);
523 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
525 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
526 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
529 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
530 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
531 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
533 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
534 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
535 phCertStore, ppvContext);
538 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
539 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
541 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
542 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
546 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
548 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
549 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
552 TRACE("returning %d\n", ret);
556 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
557 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
558 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
565 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
567 bytesNeeded = sizeof(WCHAR);
570 *pcbFormat = bytesNeeded;
573 else if (*pcbFormat < bytesNeeded)
575 *pcbFormat = bytesNeeded;
576 SetLastError(ERROR_MORE_DATA);
581 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
582 static const WCHAR endFmt[] = { '%','0','2','x',0 };
584 LPWSTR ptr = pbFormat;
586 *pcbFormat = bytesNeeded;
589 for (i = 0; i < cbEncoded; i++)
591 if (i < cbEncoded - 1)
592 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
594 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
604 #define MAX_STRING_RESOURCE_LEN 128
606 static BOOL CRYPT_FormatHexStringWithPrefix(CRYPT_DATA_BLOB *blob, int id,
607 LPWSTR str, DWORD *pcbStr)
609 WCHAR buf[MAX_STRING_RESOURCE_LEN];
613 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
614 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
615 blob->pbData, blob->cbData, NULL, &bytesNeeded);
616 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
619 *pcbStr = bytesNeeded;
622 else if (*pcbStr < bytesNeeded)
624 *pcbStr = bytesNeeded;
625 SetLastError(ERROR_MORE_DATA);
630 *pcbStr = bytesNeeded;
633 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
634 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
635 blob->pbData, blob->cbData, str, &bytesNeeded);
640 static BOOL CRYPT_FormatKeyId(CRYPT_DATA_BLOB *keyId, LPWSTR str,
643 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
646 static BOOL CRYPT_FormatCertSerialNumber(CRYPT_DATA_BLOB *serialNum, LPWSTR str,
649 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
653 static const WCHAR crlf[] = { '\r','\n',0 };
655 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType,
656 CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
659 WCHAR buf[MAX_STRING_RESOURCE_LEN];
660 WCHAR mask[MAX_STRING_RESOURCE_LEN];
663 DWORD bytesNeeded = sizeof(WCHAR);
665 switch (entry->dwAltNameChoice)
667 case CERT_ALT_NAME_RFC822_NAME:
668 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
669 sizeof(buf) / sizeof(buf[0]));
670 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
673 case CERT_ALT_NAME_DNS_NAME:
674 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
675 sizeof(buf) / sizeof(buf[0]));
676 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
679 case CERT_ALT_NAME_URL:
680 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
681 sizeof(buf) / sizeof(buf[0]));
682 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
685 case CERT_ALT_NAME_IP_ADDRESS:
687 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
688 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
690 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
693 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
694 sizeof(buf) / sizeof(buf[0]));
695 if (entry->u.IPAddress.cbData == 8)
697 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
699 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
700 sizeof(mask) / sizeof(mask[0]));
701 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
702 sprintfW(ipAddrBuf, ipAddrFmt,
703 entry->u.IPAddress.pbData[0],
704 entry->u.IPAddress.pbData[1],
705 entry->u.IPAddress.pbData[2],
706 entry->u.IPAddress.pbData[3]);
707 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
708 sprintfW(maskBuf, ipAddrFmt,
709 entry->u.IPAddress.pbData[4],
710 entry->u.IPAddress.pbData[5],
711 entry->u.IPAddress.pbData[6],
712 entry->u.IPAddress.pbData[7]);
713 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
714 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
718 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
719 entry->u.IPAddress.pbData[0],
720 entry->u.IPAddress.pbData[1],
721 entry->u.IPAddress.pbData[2],
722 entry->u.IPAddress.pbData[3],
723 entry->u.IPAddress.pbData[4],
724 entry->u.IPAddress.pbData[5],
725 entry->u.IPAddress.pbData[6],
726 entry->u.IPAddress.pbData[7]);
727 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
733 FIXME("unknown IP address format (%d bytes)\n",
734 entry->u.IPAddress.cbData);
740 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
745 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
747 *pcbStr = bytesNeeded;
748 else if (*pcbStr < bytesNeeded)
750 *pcbStr = bytesNeeded;
751 SetLastError(ERROR_MORE_DATA);
756 *pcbStr = bytesNeeded;
759 switch (entry->dwAltNameChoice)
761 case CERT_ALT_NAME_RFC822_NAME:
762 case CERT_ALT_NAME_DNS_NAME:
763 case CERT_ALT_NAME_URL:
764 strcpyW(str, entry->u.pwszURL);
766 case CERT_ALT_NAME_IP_ADDRESS:
767 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
769 strcpyW(str, ipAddrBuf);
770 str += strlenW(ipAddrBuf);
772 str += strlenW(crlf);
774 str += strlenW(mask);
775 strcpyW(str, maskBuf);
778 strcpyW(str, ipAddrBuf);
786 static const WCHAR commaSpace[] = { ',',' ',0 };
788 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType,
789 CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
791 DWORD i, size, bytesNeeded = 0;
796 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
799 sepLen = strlenW(crlf) * sizeof(WCHAR);
804 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
807 for (i = 0; ret && i < name->cAltEntry; i++)
809 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, &name->rgAltEntry[i],
813 bytesNeeded += size - sizeof(WCHAR);
814 if (i < name->cAltEntry - 1)
815 bytesNeeded += sepLen;
820 bytesNeeded += sizeof(WCHAR);
822 *pcbStr = bytesNeeded;
823 else if (*pcbStr < bytesNeeded)
825 *pcbStr = bytesNeeded;
826 SetLastError(ERROR_MORE_DATA);
831 *pcbStr = bytesNeeded;
832 for (i = 0; ret && i < name->cAltEntry; i++)
834 ret = CRYPT_FormatAltNameEntry(dwFormatStrType,
835 &name->rgAltEntry[i], str, &size);
838 str += size / sizeof(WCHAR) - 1;
839 if (i < name->cAltEntry - 1)
842 str += sepLen / sizeof(WCHAR);
851 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
852 CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
854 WCHAR buf[MAX_STRING_RESOURCE_LEN];
858 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
859 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, issuer, NULL, &bytesNeeded);
860 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
864 *pcbStr = bytesNeeded;
865 else if (*pcbStr < bytesNeeded)
867 *pcbStr = bytesNeeded;
868 SetLastError(ERROR_MORE_DATA);
873 *pcbStr = bytesNeeded;
876 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
877 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, issuer, str,
884 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
885 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
886 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
889 CERT_AUTHORITY_KEY_ID2_INFO *info;
895 SetLastError(E_INVALIDARG);
898 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
899 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
901 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
904 BOOL needSeparator = FALSE;
906 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
909 sepLen = strlenW(crlf) * sizeof(WCHAR);
914 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
917 if (info->KeyId.cbData)
919 needSeparator = TRUE;
920 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
923 /* don't include NULL-terminator more than once */
924 bytesNeeded += size - sizeof(WCHAR);
927 if (info->AuthorityCertIssuer.cAltEntry)
930 bytesNeeded += sepLen;
931 needSeparator = TRUE;
932 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
933 &info->AuthorityCertIssuer, NULL, &size);
936 /* don't include NULL-terminator more than once */
937 bytesNeeded += size - sizeof(WCHAR);
940 if (info->AuthorityCertSerialNumber.cbData)
943 bytesNeeded += sepLen;
944 ret = CRYPT_FormatCertSerialNumber(
945 &info->AuthorityCertSerialNumber, NULL, &size);
948 /* don't include NULL-terminator more than once */
949 bytesNeeded += size - sizeof(WCHAR);
955 *pcbFormat = bytesNeeded;
956 else if (*pcbFormat < bytesNeeded)
958 *pcbFormat = bytesNeeded;
959 SetLastError(ERROR_MORE_DATA);
964 LPWSTR str = pbFormat;
966 *pcbFormat = bytesNeeded;
967 needSeparator = FALSE;
968 if (info->KeyId.cbData)
970 needSeparator = TRUE;
971 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
973 str += size / sizeof(WCHAR);
975 if (info->AuthorityCertIssuer.cAltEntry)
980 str += sepLen / sizeof(WCHAR);
982 needSeparator = TRUE;
983 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
984 &info->AuthorityCertIssuer, str, &size);
986 str += size / sizeof(WCHAR);
988 if (info->AuthorityCertSerialNumber.cbData)
993 str += sepLen / sizeof(WCHAR);
995 ret = CRYPT_FormatCertSerialNumber(
996 &info->AuthorityCertSerialNumber, str, &size);
1005 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
1006 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
1008 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
1009 DWORD formatStrType, LPCSTR lpszStructType)
1011 CryptFormatObjectFunc format = NULL;
1013 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
1015 SetLastError(ERROR_FILE_NOT_FOUND);
1018 if (!HIWORD(lpszStructType))
1020 switch (LOWORD(lpszStructType))
1022 case LOWORD(X509_AUTHORITY_KEY_ID2):
1023 format = CRYPT_FormatAuthorityKeyId2;
1027 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
1028 format = CRYPT_FormatAuthorityKeyId2;
1029 if (!format && !(formatStrType & CRYPT_FORMAT_STR_NO_HEX))
1030 format = CRYPT_FormatHexString;
1034 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
1035 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
1036 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
1038 CryptFormatObjectFunc format = NULL;
1039 HCRYPTOIDFUNCADDR hFunc = NULL;
1042 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
1043 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
1044 pbEncoded, cbEncoded, pbFormat, pcbFormat);
1046 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
1047 dwFormatStrType, lpszStructType)))
1049 static HCRYPTOIDFUNCSET set = NULL;
1052 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
1053 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
1054 (void **)&format, &hFunc);
1057 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
1058 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
1061 CryptFreeOIDFunctionAddress(hFunc, 0);