crypt32: Implement CryptFormatObject for szOID_BASIC_CONSTRAINTS2.
[wine/multimedia.git] / dlls / crypt32 / object.c
blob783dbce9baaf8cc5969b91c7a49dafb4997fe5fb
1 /*
2 * crypt32 Crypt*Object functions
4 * Copyright 2007 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #define NONAMELESSUNION
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wincrypt.h"
25 #include "mssip.h"
26 #include "winuser.h"
27 #include "crypt32_private.h"
28 #include "cryptres.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)
36 BOOL ret = FALSE;
37 HANDLE file;
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)
45 ret = TRUE;
46 blob->cbData = GetFileSize(file, NULL);
47 if (blob->cbData)
49 blob->pbData = CryptMemAlloc(blob->cbData);
50 if (blob->pbData)
52 DWORD read;
54 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
57 CloseHandle(file);
59 TRACE("returning %d\n", ret);
60 return ret;
63 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
64 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
65 DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
67 CERT_BLOB fileBlob;
68 const CERT_BLOB *blob;
69 HCERTSTORE store;
70 DWORD contentType;
71 BOOL ret;
73 switch (dwObjectType)
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);
80 blob = &fileBlob;
81 break;
82 case CERT_QUERY_OBJECT_BLOB:
83 blob = (const CERT_BLOB *)pvObject;
84 ret = TRUE;
85 break;
86 default:
87 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
88 ret = FALSE;
90 if (!ret)
91 return FALSE;
93 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
94 CERT_STORE_CREATE_NEW_FLAG, NULL);
95 ret = FALSE;
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);
100 if (ret)
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);
107 if (ret)
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);
114 if (ret)
115 contentType = CERT_QUERY_CONTENT_CTL;
117 if (ret)
119 if (pdwMsgAndCertEncodingType)
120 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
121 if (pdwContentType)
122 *pdwContentType = contentType;
123 if (phCertStore)
124 *phCertStore = CertDuplicateStore(store);
126 CertCloseStore(store, 0);
127 if (blob == &fileBlob)
128 CryptMemFree(blob->pbData);
129 TRACE("returning %d\n", ret);
130 return 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)
138 CERT_BLOB fileBlob;
139 const CERT_BLOB *blob;
140 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
141 const void *context;
142 DWORD contextType;
143 BOOL ret;
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);
152 blob = &fileBlob;
153 break;
154 case CERT_QUERY_OBJECT_BLOB:
155 blob = (const CERT_BLOB *)pvObject;
156 ret = TRUE;
157 break;
158 default:
159 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
160 ret = FALSE;
162 if (!ret)
163 return FALSE;
165 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
166 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
167 if (context)
169 DWORD contentType, certStoreOffset;
171 ret = TRUE;
172 switch (contextType)
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);
182 ret = FALSE;
183 goto end;
185 break;
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);
194 ret = FALSE;
195 goto end;
197 break;
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);
206 ret = FALSE;
207 goto end;
209 break;
210 default:
211 SetLastError(ERROR_INVALID_DATA);
212 ret = FALSE;
213 goto end;
215 if (pdwMsgAndCertEncodingType)
216 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
217 if (pdwContentType)
218 *pdwContentType = contentType;
219 if (phCertStore)
220 *phCertStore = CertDuplicateStore(
221 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
222 if (ppvContext)
223 *ppvContext = contextInterface->duplicate(context);
226 end:
227 if (contextInterface && context)
228 contextInterface->free(context);
229 if (blob == &fileBlob)
230 CryptMemFree(blob->pbData);
231 TRACE("returning %d\n", ret);
232 return 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;
240 HANDLE file;
241 BOOL ret = FALSE;
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? */
247 return FALSE;
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);
258 if (ret)
260 if (pdwMsgAndCertEncodingType)
261 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
262 if (pdwContentType)
263 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
264 if (phCertStore)
265 *phCertStore = CertDuplicateStore(store);
267 CertCloseStore(store, 0);
268 CloseHandle(file);
270 TRACE("returning %d\n", ret);
271 return 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)
279 CERT_BLOB fileBlob;
280 const CERT_BLOB *blob;
281 BOOL ret;
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
289 * directly
291 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
292 blob = &fileBlob;
293 break;
294 case CERT_QUERY_OBJECT_BLOB:
295 blob = (const CERT_BLOB *)pvObject;
296 ret = TRUE;
297 break;
298 default:
299 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
300 ret = FALSE;
302 if (!ret)
303 return FALSE;
305 ret = FALSE;
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);
311 if (msg)
313 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
314 if (ret)
316 DWORD type, len = sizeof(type);
318 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
319 if (ret)
321 if ((dwExpectedContentTypeFlags &
322 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
324 if (type != CMSG_SIGNED)
326 SetLastError(ERROR_INVALID_DATA);
327 ret = FALSE;
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);
338 ret = FALSE;
340 else if (pdwContentType)
341 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
345 if (!ret)
347 CryptMsgClose(msg);
348 msg = NULL;
352 /* Failing that, try explicitly typed messages */
353 if (!ret &&
354 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
356 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
357 if (msg)
359 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
360 if (!ret)
362 CryptMsgClose(msg);
363 msg = NULL;
366 if (msg && pdwContentType)
367 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
369 if (!ret &&
370 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
372 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
373 if (msg)
375 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
376 if (!ret)
378 CryptMsgClose(msg);
379 msg = NULL;
382 if (msg && pdwContentType)
383 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
385 if (pdwMsgAndCertEncodingType)
386 *pdwMsgAndCertEncodingType = encodingType;
387 if (msg)
389 if (phMsg)
390 *phMsg = msg;
391 if (phCertStore)
392 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
393 0, msg);
395 if (blob == &fileBlob)
396 CryptMemFree(blob->pbData);
397 TRACE("returning %d\n", ret);
398 return ret;
401 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
402 const void *pvObject, DWORD dwExpectedContentTypeFlags,
403 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
404 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
406 HANDLE file;
407 GUID subject;
408 BOOL ret = FALSE;
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",
415 dwObjectType);
416 SetLastError(E_INVALIDARG);
417 return FALSE;
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);
424 if (ret)
426 SIP_DISPATCH_INFO sip;
428 memset(&sip, 0, sizeof(sip));
429 sip.cbSize = sizeof(sip);
430 ret = CryptSIPLoad(&subject, 0, &sip);
431 if (ret)
433 SIP_SUBJECTINFO subjectInfo;
434 CERT_BLOB blob;
435 DWORD encodingType;
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,
443 NULL);
444 if (ret)
446 blob.pbData = CryptMemAlloc(blob.cbData);
447 if (blob.pbData)
449 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
450 &blob.cbData, blob.pbData);
451 if (ret)
453 ret = CRYPT_QueryMessageObject(
454 CERT_QUERY_OBJECT_BLOB, &blob,
455 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
456 pdwMsgAndCertEncodingType, NULL, phCertStore,
457 phMsg);
458 if (ret && pdwContentType)
459 *pdwContentType =
460 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
462 CryptMemFree(blob.pbData);
464 else
466 SetLastError(ERROR_OUTOFMEMORY);
467 ret = FALSE;
472 CloseHandle(file);
474 TRACE("returning %d\n", ret);
475 return 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;
487 BOOL ret = TRUE;
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);
501 return FALSE;
503 if (pdwFormatType)
504 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
506 if (phCertStore)
507 *phCertStore = NULL;
508 if (phMsg)
509 *phMsg = NULL;
510 if (ppvContext)
511 *ppvContext = NULL;
513 ret = FALSE;
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);
522 if (!ret &&
523 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
525 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
526 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
528 if (!ret &&
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);
537 if (!ret &&
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,
543 phCertStore, phMsg);
545 if (!ret &&
546 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
548 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
549 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
550 phCertStore, phMsg);
552 TRACE("returning %d\n", ret);
553 return 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,
559 DWORD *pcbFormat)
561 BOOL ret;
562 DWORD bytesNeeded;
564 if (cbEncoded)
565 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
566 else
567 bytesNeeded = sizeof(WCHAR);
568 if (!pbFormat)
570 *pcbFormat = bytesNeeded;
571 ret = TRUE;
573 else if (*pcbFormat < bytesNeeded)
575 *pcbFormat = bytesNeeded;
576 SetLastError(ERROR_MORE_DATA);
577 ret = FALSE;
579 else
581 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
582 static const WCHAR endFmt[] = { '%','0','2','x',0 };
583 DWORD i;
584 LPWSTR ptr = pbFormat;
586 *pcbFormat = bytesNeeded;
587 if (cbEncoded)
589 for (i = 0; i < cbEncoded; i++)
591 if (i < cbEncoded - 1)
592 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
593 else
594 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
597 else
598 *ptr = 0;
599 ret = TRUE;
601 return ret;
604 #define MAX_STRING_RESOURCE_LEN 128
606 static const WCHAR crlf[] = { '\r','\n',0 };
607 static const WCHAR commaSpace[] = { ',',' ',0 };
609 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
610 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
611 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
612 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
614 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
615 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
616 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
617 DWORD *pcbFormat)
619 DWORD size;
620 CERT_BASIC_CONSTRAINTS2_INFO *info;
621 BOOL ret;
623 if (!cbEncoded)
625 SetLastError(E_INVALIDARG);
626 return FALSE;
628 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
629 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
631 static const WCHAR pathFmt[] = { '%','d',0 };
632 static BOOL stringsLoaded = FALSE;
633 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
634 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
635 LPCWSTR sep, subjectType;
636 DWORD sepLen;
638 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
640 sep = crlf;
641 sepLen = strlenW(crlf) * sizeof(WCHAR);
643 else
645 sep = commaSpace;
646 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
649 if (!stringsLoaded)
651 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
652 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
653 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
654 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
655 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
656 subjectTypeEndCert,
657 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
658 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
659 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
660 stringsLoaded = TRUE;
662 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
663 if (info->fCA)
664 subjectType = subjectTypeCA;
665 else
666 subjectType = subjectTypeEndCert;
667 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
668 bytesNeeded += sepLen;
669 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
670 if (info->fPathLenConstraint)
671 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
672 else
673 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
674 sizeof(pathLength) / sizeof(pathLength[0]));
675 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
676 if (!pbFormat)
677 *pcbFormat = bytesNeeded;
678 else if (*pcbFormat < bytesNeeded)
680 *pcbFormat = bytesNeeded;
681 SetLastError(ERROR_MORE_DATA);
682 ret = FALSE;
684 else
686 LPWSTR str = pbFormat;
688 *pcbFormat = bytesNeeded;
689 strcpyW(str, subjectTypeHeader);
690 str += strlenW(subjectTypeHeader);
691 strcpyW(str, subjectType);
692 str += strlenW(subjectType);
693 strcpyW(str, sep);
694 str += sepLen / sizeof(WCHAR);
695 strcpyW(str, pathLengthHeader);
696 str += strlenW(pathLengthHeader);
697 strcpyW(str, pathLength);
698 str += strlenW(pathLength);
700 LocalFree(info);
702 return ret;
705 static BOOL CRYPT_FormatHexStringWithPrefix(CRYPT_DATA_BLOB *blob, int id,
706 LPWSTR str, DWORD *pcbStr)
708 WCHAR buf[MAX_STRING_RESOURCE_LEN];
709 DWORD bytesNeeded;
710 BOOL ret;
712 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
713 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
714 blob->pbData, blob->cbData, NULL, &bytesNeeded);
715 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
716 if (!str)
718 *pcbStr = bytesNeeded;
719 ret = TRUE;
721 else if (*pcbStr < bytesNeeded)
723 *pcbStr = bytesNeeded;
724 SetLastError(ERROR_MORE_DATA);
725 ret = FALSE;
727 else
729 *pcbStr = bytesNeeded;
730 strcpyW(str, buf);
731 str += strlenW(str);
732 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
733 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
734 blob->pbData, blob->cbData, str, &bytesNeeded);
736 return ret;
739 static BOOL CRYPT_FormatKeyId(CRYPT_DATA_BLOB *keyId, LPWSTR str,
740 DWORD *pcbStr)
742 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
745 static BOOL CRYPT_FormatCertSerialNumber(CRYPT_DATA_BLOB *serialNum, LPWSTR str,
746 DWORD *pcbStr)
748 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
749 str, pcbStr);
752 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType,
753 CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
755 BOOL ret;
756 WCHAR buf[MAX_STRING_RESOURCE_LEN];
757 WCHAR mask[MAX_STRING_RESOURCE_LEN];
758 WCHAR ipAddrBuf[32];
759 WCHAR maskBuf[16];
760 DWORD bytesNeeded = sizeof(WCHAR);
762 switch (entry->dwAltNameChoice)
764 case CERT_ALT_NAME_RFC822_NAME:
765 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
766 sizeof(buf) / sizeof(buf[0]));
767 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
768 ret = TRUE;
769 break;
770 case CERT_ALT_NAME_DNS_NAME:
771 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
772 sizeof(buf) / sizeof(buf[0]));
773 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
774 ret = TRUE;
775 break;
776 case CERT_ALT_NAME_URL:
777 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
778 sizeof(buf) / sizeof(buf[0]));
779 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
780 ret = TRUE;
781 break;
782 case CERT_ALT_NAME_IP_ADDRESS:
784 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
785 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
787 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
788 '.','%','d',0 };
790 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
791 sizeof(buf) / sizeof(buf[0]));
792 if (entry->u.IPAddress.cbData == 8)
794 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
796 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
797 sizeof(mask) / sizeof(mask[0]));
798 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
799 sprintfW(ipAddrBuf, ipAddrFmt,
800 entry->u.IPAddress.pbData[0],
801 entry->u.IPAddress.pbData[1],
802 entry->u.IPAddress.pbData[2],
803 entry->u.IPAddress.pbData[3]);
804 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
805 sprintfW(maskBuf, ipAddrFmt,
806 entry->u.IPAddress.pbData[4],
807 entry->u.IPAddress.pbData[5],
808 entry->u.IPAddress.pbData[6],
809 entry->u.IPAddress.pbData[7]);
810 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
811 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
813 else
815 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
816 entry->u.IPAddress.pbData[0],
817 entry->u.IPAddress.pbData[1],
818 entry->u.IPAddress.pbData[2],
819 entry->u.IPAddress.pbData[3],
820 entry->u.IPAddress.pbData[4],
821 entry->u.IPAddress.pbData[5],
822 entry->u.IPAddress.pbData[6],
823 entry->u.IPAddress.pbData[7]);
824 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
826 ret = TRUE;
828 else
830 FIXME("unknown IP address format (%d bytes)\n",
831 entry->u.IPAddress.cbData);
832 ret = FALSE;
834 break;
836 default:
837 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
838 ret = FALSE;
840 if (ret)
842 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
843 if (!str)
844 *pcbStr = bytesNeeded;
845 else if (*pcbStr < bytesNeeded)
847 *pcbStr = bytesNeeded;
848 SetLastError(ERROR_MORE_DATA);
849 ret = FALSE;
851 else
853 *pcbStr = bytesNeeded;
854 strcpyW(str, buf);
855 str += strlenW(str);
856 switch (entry->dwAltNameChoice)
858 case CERT_ALT_NAME_RFC822_NAME:
859 case CERT_ALT_NAME_DNS_NAME:
860 case CERT_ALT_NAME_URL:
861 strcpyW(str, entry->u.pwszURL);
862 break;
863 case CERT_ALT_NAME_IP_ADDRESS:
864 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
866 strcpyW(str, ipAddrBuf);
867 str += strlenW(ipAddrBuf);
868 strcpyW(str, crlf);
869 str += strlenW(crlf);
870 strcpyW(str, mask);
871 str += strlenW(mask);
872 strcpyW(str, maskBuf);
874 else
875 strcpyW(str, ipAddrBuf);
876 break;
880 return ret;
883 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType,
884 CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
886 DWORD i, size, bytesNeeded = 0;
887 BOOL ret = TRUE;
888 LPCWSTR sep;
889 DWORD sepLen;
891 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
893 sep = crlf;
894 sepLen = strlenW(crlf) * sizeof(WCHAR);
896 else
898 sep = commaSpace;
899 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
902 for (i = 0; ret && i < name->cAltEntry; i++)
904 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, &name->rgAltEntry[i],
905 NULL, &size);
906 if (ret)
908 bytesNeeded += size - sizeof(WCHAR);
909 if (i < name->cAltEntry - 1)
910 bytesNeeded += sepLen;
913 if (ret)
915 bytesNeeded += sizeof(WCHAR);
916 if (!str)
917 *pcbStr = bytesNeeded;
918 else if (*pcbStr < bytesNeeded)
920 *pcbStr = bytesNeeded;
921 SetLastError(ERROR_MORE_DATA);
922 ret = FALSE;
924 else
926 *pcbStr = bytesNeeded;
927 for (i = 0; ret && i < name->cAltEntry; i++)
929 ret = CRYPT_FormatAltNameEntry(dwFormatStrType,
930 &name->rgAltEntry[i], str, &size);
931 if (ret)
933 str += size / sizeof(WCHAR) - 1;
934 if (i < name->cAltEntry - 1)
936 strcpyW(str, sep);
937 str += sepLen / sizeof(WCHAR);
943 return ret;
946 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
947 CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
949 WCHAR buf[MAX_STRING_RESOURCE_LEN];
950 DWORD bytesNeeded;
951 BOOL ret;
953 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
954 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, issuer, NULL, &bytesNeeded);
955 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
956 if (ret)
958 if (!str)
959 *pcbStr = bytesNeeded;
960 else if (*pcbStr < bytesNeeded)
962 *pcbStr = bytesNeeded;
963 SetLastError(ERROR_MORE_DATA);
964 ret = FALSE;
966 else
968 *pcbStr = bytesNeeded;
969 strcpyW(str, buf);
970 str += strlenW(str);
971 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
972 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, issuer, str,
973 &bytesNeeded);
976 return ret;
979 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
980 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
981 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
982 DWORD *pcbFormat)
984 CERT_AUTHORITY_KEY_ID2_INFO *info;
985 DWORD size;
986 BOOL ret = FALSE;
988 if (!cbEncoded)
990 SetLastError(E_INVALIDARG);
991 return FALSE;
993 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
994 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
996 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
997 LPCWSTR sep;
998 DWORD sepLen;
999 BOOL needSeparator = FALSE;
1001 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1003 sep = crlf;
1004 sepLen = strlenW(crlf) * sizeof(WCHAR);
1006 else
1008 sep = commaSpace;
1009 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1012 if (info->KeyId.cbData)
1014 needSeparator = TRUE;
1015 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1016 if (ret)
1018 /* don't include NULL-terminator more than once */
1019 bytesNeeded += size - sizeof(WCHAR);
1022 if (info->AuthorityCertIssuer.cAltEntry)
1024 if (needSeparator)
1025 bytesNeeded += sepLen;
1026 needSeparator = TRUE;
1027 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1028 &info->AuthorityCertIssuer, NULL, &size);
1029 if (ret)
1031 /* don't include NULL-terminator more than once */
1032 bytesNeeded += size - sizeof(WCHAR);
1035 if (info->AuthorityCertSerialNumber.cbData)
1037 if (needSeparator)
1038 bytesNeeded += sepLen;
1039 ret = CRYPT_FormatCertSerialNumber(
1040 &info->AuthorityCertSerialNumber, NULL, &size);
1041 if (ret)
1043 /* don't include NULL-terminator more than once */
1044 bytesNeeded += size - sizeof(WCHAR);
1047 if (ret)
1049 if (!pbFormat)
1050 *pcbFormat = bytesNeeded;
1051 else if (*pcbFormat < bytesNeeded)
1053 *pcbFormat = bytesNeeded;
1054 SetLastError(ERROR_MORE_DATA);
1055 ret = FALSE;
1057 else
1059 LPWSTR str = pbFormat;
1061 *pcbFormat = bytesNeeded;
1062 needSeparator = FALSE;
1063 if (info->KeyId.cbData)
1065 needSeparator = TRUE;
1066 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1067 if (ret)
1068 str += size / sizeof(WCHAR);
1070 if (info->AuthorityCertIssuer.cAltEntry)
1072 if (needSeparator)
1074 strcpyW(str, sep);
1075 str += sepLen / sizeof(WCHAR);
1077 needSeparator = TRUE;
1078 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1079 &info->AuthorityCertIssuer, str, &size);
1080 if (ret)
1081 str += size / sizeof(WCHAR);
1083 if (info->AuthorityCertSerialNumber.cbData)
1085 if (needSeparator)
1087 strcpyW(str, sep);
1088 str += sepLen / sizeof(WCHAR);
1090 ret = CRYPT_FormatCertSerialNumber(
1091 &info->AuthorityCertSerialNumber, str, &size);
1095 LocalFree(info);
1097 return ret;
1100 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
1101 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1102 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1103 DWORD *pcbFormat)
1105 CERT_ENHKEY_USAGE *usage;
1106 DWORD size;
1107 BOOL ret = FALSE;
1109 if (!cbEncoded)
1111 SetLastError(E_INVALIDARG);
1112 return FALSE;
1114 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
1115 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
1117 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1118 DWORD i;
1119 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1120 LPCWSTR sep;
1121 DWORD sepLen;
1123 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1125 sep = crlf;
1126 sepLen = strlenW(crlf) * sizeof(WCHAR);
1128 else
1130 sep = commaSpace;
1131 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1134 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
1135 sizeof(unknown) / sizeof(unknown[0]));
1136 for (i = 0; i < usage->cUsageIdentifier; i++)
1138 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1139 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1141 if (info)
1142 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
1143 else
1144 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1145 bytesNeeded += sizeof(WCHAR); /* space */
1146 bytesNeeded += sizeof(WCHAR); /* left paren */
1147 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
1148 sizeof(WCHAR);
1149 bytesNeeded += sizeof(WCHAR); /* right paren */
1150 if (i < usage->cUsageIdentifier - 1)
1151 bytesNeeded += sepLen;
1153 if (!pbFormat)
1154 *pcbFormat = bytesNeeded;
1155 else if (*pcbFormat < bytesNeeded)
1157 *pcbFormat = bytesNeeded;
1158 SetLastError(ERROR_MORE_DATA);
1159 ret = FALSE;
1161 else
1163 LPWSTR str = pbFormat;
1165 *pcbFormat = bytesNeeded;
1166 for (i = 0; i < usage->cUsageIdentifier; i++)
1168 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1169 usage->rgpszUsageIdentifier[i],
1170 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
1171 LPCSTR oidPtr;
1173 if (info)
1175 strcpyW(str, info->pwszName);
1176 str += strlenW(info->pwszName);
1178 else
1180 strcpyW(str, unknown);
1181 str += strlenW(unknown);
1183 *str++ = ' ';
1184 *str++ = '(';
1185 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
1186 *str++ = *oidPtr;
1187 *str++ = ')';
1188 *str = 0;
1189 if (i < usage->cUsageIdentifier - 1)
1191 strcpyW(str, sep);
1192 str += sepLen / sizeof(WCHAR);
1196 LocalFree(usage);
1198 return ret;
1201 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
1202 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
1204 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
1205 DWORD formatStrType, LPCSTR lpszStructType)
1207 CryptFormatObjectFunc format = NULL;
1209 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
1211 SetLastError(ERROR_FILE_NOT_FOUND);
1212 return NULL;
1214 if (!HIWORD(lpszStructType))
1216 switch (LOWORD(lpszStructType))
1218 case LOWORD(X509_BASIC_CONSTRAINTS2):
1219 format = CRYPT_FormatBasicConstraints2;
1220 break;
1221 case LOWORD(X509_AUTHORITY_KEY_ID2):
1222 format = CRYPT_FormatAuthorityKeyId2;
1223 break;
1224 case LOWORD(X509_ENHANCED_KEY_USAGE):
1225 format = CRYPT_FormatEnhancedKeyUsage;
1226 break;
1229 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
1230 format = CRYPT_FormatBasicConstraints2;
1231 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
1232 format = CRYPT_FormatAuthorityKeyId2;
1233 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
1234 format = CRYPT_FormatEnhancedKeyUsage;
1235 if (!format && !(formatStrType & CRYPT_FORMAT_STR_NO_HEX))
1236 format = CRYPT_FormatHexString;
1237 return format;
1240 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
1241 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
1242 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
1244 CryptFormatObjectFunc format = NULL;
1245 HCRYPTOIDFUNCADDR hFunc = NULL;
1246 BOOL ret = FALSE;
1248 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
1249 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
1250 pbEncoded, cbEncoded, pbFormat, pcbFormat);
1252 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
1253 dwFormatStrType, lpszStructType)))
1255 static HCRYPTOIDFUNCSET set = NULL;
1257 if (!set)
1258 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
1259 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
1260 (void **)&format, &hFunc);
1262 if (format)
1263 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
1264 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
1265 pcbFormat);
1266 if (hFunc)
1267 CryptFreeOIDFunctionAddress(hFunc, 0);
1268 return ret;