cmd: DIR command outputs free space for the path.
[wine.git] / dlls / crypt32 / object.c
blob8a4a161bbfbeaa0b37a72ae52649270aefcb57e8
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>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wincrypt.h"
25 #include "mssip.h"
26 #include "winuser.h"
27 #include "wintrust.h"
28 #include "crypt32_private.h"
29 #include "cryptres.h"
30 #include "wine/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) && read == blob->cbData;
55 if (!ret) CryptMemFree(blob->pbData);
57 else
58 ret = FALSE;
60 CloseHandle(file);
62 TRACE("returning %d\n", ret);
63 return ret;
66 static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
67 DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
68 DWORD *contentType, const void **ppvContext)
70 BOOL ret = FALSE;
72 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
74 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
75 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
76 if (ret && contentType)
77 *contentType = CERT_QUERY_CONTENT_CERT;
79 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
81 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
82 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
83 if (ret && contentType)
84 *contentType = CERT_QUERY_CONTENT_CRL;
86 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
88 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
89 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
90 if (ret && contentType)
91 *contentType = CERT_QUERY_CONTENT_CTL;
93 return ret;
96 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
97 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
98 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
99 HCERTSTORE *phCertStore, const void **ppvContext)
101 CERT_BLOB fileBlob;
102 const CERT_BLOB *blob;
103 HCERTSTORE store;
104 BOOL ret;
105 DWORD formatType = 0;
107 switch (dwObjectType)
109 case CERT_QUERY_OBJECT_FILE:
110 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
111 * just read the file directly
113 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
114 blob = &fileBlob;
115 break;
116 case CERT_QUERY_OBJECT_BLOB:
117 blob = pvObject;
118 ret = TRUE;
119 break;
120 default:
121 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
122 ret = FALSE;
124 if (!ret)
125 return FALSE;
127 ret = FALSE;
128 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
129 CERT_STORE_CREATE_NEW_FLAG, NULL);
130 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
132 ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
133 pdwContentType, ppvContext);
134 if (ret)
135 formatType = CERT_QUERY_FORMAT_BINARY;
137 if (!ret &&
138 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
140 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
141 CRYPT_DATA_BLOB decoded;
143 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
144 trimmed.cbData--;
145 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
146 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
147 if (ret)
149 decoded.pbData = CryptMemAlloc(decoded.cbData);
150 if (decoded.pbData)
152 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
153 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
154 &decoded.cbData, NULL, NULL);
155 if (ret)
157 ret = CRYPT_QueryContextBlob(&decoded,
158 dwExpectedContentTypeFlags, store, pdwContentType,
159 ppvContext);
160 if (ret)
161 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
163 CryptMemFree(decoded.pbData);
165 else
166 ret = FALSE;
169 if (ret)
171 if (pdwMsgAndCertEncodingType)
172 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
173 if (pdwFormatType)
174 *pdwFormatType = formatType;
175 if (phCertStore)
176 *phCertStore = CertDuplicateStore(store);
178 CertCloseStore(store, 0);
179 if (blob == &fileBlob)
180 CryptMemFree(blob->pbData);
181 TRACE("returning %d\n", ret);
182 return ret;
185 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
186 const void *pvObject, DWORD dwExpectedContentTypeFlags,
187 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
188 HCERTSTORE *phCertStore, const void **ppvContext)
190 CERT_BLOB fileBlob;
191 const CERT_BLOB *blob;
192 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
193 const void *context;
194 DWORD contextType;
195 BOOL ret;
197 switch (dwObjectType)
199 case CERT_QUERY_OBJECT_FILE:
200 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
201 * just read the file directly
203 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
204 blob = &fileBlob;
205 break;
206 case CERT_QUERY_OBJECT_BLOB:
207 blob = pvObject;
208 ret = TRUE;
209 break;
210 default:
211 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
212 ret = FALSE;
214 if (!ret)
215 return FALSE;
217 ret = FALSE;
218 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
219 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
220 if (context)
222 DWORD contentType, certStoreOffset;
224 ret = TRUE;
225 switch (contextType)
227 case CERT_STORE_CERTIFICATE_CONTEXT:
228 contextInterface = pCertInterface;
229 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
230 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
231 if (!(dwExpectedContentTypeFlags &
232 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
234 SetLastError(ERROR_INVALID_DATA);
235 ret = FALSE;
236 goto end;
238 break;
239 case CERT_STORE_CRL_CONTEXT:
240 contextInterface = pCRLInterface;
241 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
242 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
243 if (!(dwExpectedContentTypeFlags &
244 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
246 SetLastError(ERROR_INVALID_DATA);
247 ret = FALSE;
248 goto end;
250 break;
251 case CERT_STORE_CTL_CONTEXT:
252 contextInterface = pCTLInterface;
253 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
254 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
255 if (!(dwExpectedContentTypeFlags &
256 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
258 SetLastError(ERROR_INVALID_DATA);
259 ret = FALSE;
260 goto end;
262 break;
263 default:
264 SetLastError(ERROR_INVALID_DATA);
265 ret = FALSE;
266 goto end;
268 if (pdwMsgAndCertEncodingType)
269 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
270 if (pdwContentType)
271 *pdwContentType = contentType;
272 if (phCertStore)
273 *phCertStore = CertDuplicateStore(
274 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
275 if (ppvContext)
277 *ppvContext = context;
278 Context_AddRef(context_from_ptr(context));
282 end:
283 if (contextInterface && context)
284 Context_Release(context_from_ptr(context));
285 if (blob == &fileBlob)
286 CryptMemFree(blob->pbData);
287 TRACE("returning %d\n", ret);
288 return ret;
291 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
292 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
293 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
295 HANDLE file;
296 BOOL ret = FALSE;
298 TRACE("%s\n", debugstr_w(fileName));
299 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
300 OPEN_EXISTING, 0, NULL);
301 if (file != INVALID_HANDLE_VALUE)
303 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
304 CERT_STORE_CREATE_NEW_FLAG, NULL);
306 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
307 if (ret)
309 if (pdwMsgAndCertEncodingType)
310 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
311 if (pdwContentType)
312 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
313 if (phCertStore)
314 *phCertStore = CertDuplicateStore(store);
316 CertCloseStore(store, 0);
317 CloseHandle(file);
319 TRACE("returning %d\n", ret);
320 return ret;
323 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
324 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
325 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
327 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
328 CERT_STORE_CREATE_NEW_FLAG, NULL);
329 BOOL ret;
331 TRACE("(%ld, %p)\n", blob->cbData, blob->pbData);
333 ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
334 if (ret)
336 if (pdwMsgAndCertEncodingType)
337 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
338 if (pdwContentType)
339 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
340 if (phCertStore)
341 *phCertStore = CertDuplicateStore(store);
343 CertCloseStore(store, 0);
344 TRACE("returning %d\n", ret);
345 return ret;
348 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
349 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
350 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
352 switch (dwObjectType)
354 case CERT_QUERY_OBJECT_FILE:
355 return CRYPT_QuerySerializedStoreFromFile(pvObject,
356 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
357 case CERT_QUERY_OBJECT_BLOB:
358 return CRYPT_QuerySerializedStoreFromBlob(pvObject,
359 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
360 default:
361 FIXME("unimplemented for type %ld\n", dwObjectType);
362 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
363 return FALSE;
367 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
368 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
370 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
371 BOOL ret = FALSE;
372 HCRYPTMSG msg;
374 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
376 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
377 if (ret)
379 DWORD type, len = sizeof(type);
381 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
382 if (ret)
384 if (type != CMSG_SIGNED)
386 SetLastError(ERROR_INVALID_DATA);
387 ret = FALSE;
391 if (!ret)
393 CryptMsgClose(msg);
394 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
395 NULL);
396 if (msg)
398 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
399 if (!ret)
401 CryptMsgClose(msg);
402 msg = NULL;
407 if (ret)
409 if (pdwMsgAndCertEncodingType)
410 *pdwMsgAndCertEncodingType = encodingType;
411 if (pdwContentType)
412 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
413 if (phMsg)
414 *phMsg = msg;
416 return ret;
419 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
420 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
422 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
423 BOOL ret = FALSE;
424 HCRYPTMSG msg;
426 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
428 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
429 if (ret)
431 DWORD type, len = sizeof(type);
433 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
434 if (ret)
436 if (type != CMSG_DATA)
438 SetLastError(ERROR_INVALID_DATA);
439 ret = FALSE;
443 if (!ret)
445 CryptMsgClose(msg);
446 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
447 NULL, NULL);
448 if (msg)
450 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
451 if (!ret)
453 CryptMsgClose(msg);
454 msg = NULL;
459 if (ret)
461 if (pdwMsgAndCertEncodingType)
462 *pdwMsgAndCertEncodingType = encodingType;
463 if (pdwContentType)
464 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
465 if (phMsg)
466 *phMsg = msg;
468 return ret;
471 /* Used to decode non-embedded messages */
472 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
473 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
474 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
475 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
477 CERT_BLOB fileBlob;
478 const CERT_BLOB *blob;
479 BOOL ret;
480 HCRYPTMSG msg = NULL;
481 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
482 DWORD formatType = 0;
484 TRACE("(%ld, %p, %08lx, %08lx, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
485 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
486 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
487 phMsg);
489 switch (dwObjectType)
491 case CERT_QUERY_OBJECT_FILE:
492 /* This isn't an embedded PKCS7 message, so just read the file
493 * directly
495 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
496 blob = &fileBlob;
497 break;
498 case CERT_QUERY_OBJECT_BLOB:
499 blob = pvObject;
500 ret = TRUE;
501 break;
502 default:
503 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
504 ret = FALSE;
506 if (!ret)
507 return FALSE;
509 ret = FALSE;
510 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
512 /* Try it first as a signed message */
513 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
514 ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
515 pdwContentType, &msg);
516 /* Failing that, try as an unsigned message */
517 if (!ret &&
518 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
519 ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
520 pdwContentType, &msg);
521 if (ret)
522 formatType = CERT_QUERY_FORMAT_BINARY;
524 if (!ret &&
525 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
527 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
528 CRYPT_DATA_BLOB decoded;
530 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
531 trimmed.cbData--;
532 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
533 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
534 if (ret)
536 decoded.pbData = CryptMemAlloc(decoded.cbData);
537 if (decoded.pbData)
539 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
540 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
541 &decoded.cbData, NULL, NULL);
542 if (ret)
544 /* Try it first as a signed message */
545 if (dwExpectedContentTypeFlags &
546 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
547 ret = CRYPT_QuerySignedMessage(&decoded,
548 pdwMsgAndCertEncodingType, pdwContentType, &msg);
549 /* Failing that, try as an unsigned message */
550 if (!ret && (dwExpectedContentTypeFlags &
551 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
552 ret = CRYPT_QueryUnsignedMessage(&decoded,
553 pdwMsgAndCertEncodingType, pdwContentType, &msg);
554 if (ret)
555 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
557 CryptMemFree(decoded.pbData);
559 else
560 ret = FALSE;
562 if (!ret && !(blob->cbData % sizeof(WCHAR)))
564 CRYPT_DATA_BLOB decoded;
565 LPWSTR str = (LPWSTR)blob->pbData;
566 DWORD strLen = blob->cbData / sizeof(WCHAR);
568 /* Try again, assuming the input string is UTF-16 base64 */
569 while (strLen && !str[strLen - 1])
570 strLen--;
571 ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
572 NULL, &decoded.cbData, NULL, NULL);
573 if (ret)
575 decoded.pbData = CryptMemAlloc(decoded.cbData);
576 if (decoded.pbData)
578 ret = CryptStringToBinaryW(str, strLen,
579 CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
580 NULL, NULL);
581 if (ret)
583 /* Try it first as a signed message */
584 if (dwExpectedContentTypeFlags &
585 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
586 ret = CRYPT_QuerySignedMessage(&decoded,
587 pdwMsgAndCertEncodingType, pdwContentType, &msg);
588 /* Failing that, try as an unsigned message */
589 if (!ret && (dwExpectedContentTypeFlags &
590 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
591 ret = CRYPT_QueryUnsignedMessage(&decoded,
592 pdwMsgAndCertEncodingType, pdwContentType, &msg);
593 if (ret)
594 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
596 CryptMemFree(decoded.pbData);
598 else
599 ret = FALSE;
603 if (ret)
605 if (pdwFormatType)
606 *pdwFormatType = formatType;
607 if (phCertStore)
608 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
609 0, msg);
610 if (phMsg)
611 *phMsg = msg;
612 else
613 CryptMsgClose(msg);
615 if (blob == &fileBlob)
616 CryptMemFree(blob->pbData);
617 TRACE("returning %d\n", ret);
618 return ret;
621 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
622 const void *pvObject, DWORD dwExpectedContentTypeFlags,
623 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
624 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
626 HANDLE file;
627 GUID subject;
628 BOOL ret = FALSE;
630 TRACE("%s\n", debugstr_w(pvObject));
632 if (dwObjectType == CERT_QUERY_OBJECT_BLOB)
634 WCHAR temp_path[MAX_PATH], temp_name[MAX_PATH];
635 const CERT_BLOB *b = pvObject;
637 TRACE("cbData %lu, pbData %p.\n", b->cbData, b->pbData);
639 if (!GetTempPathW(MAX_PATH, temp_path) || !GetTempFileNameW(temp_path, L"blb", 0, temp_name))
641 ERR("Failed getting temp file name.\n");
642 return FALSE;
644 file = CreateFileW(temp_name, GENERIC_READ | GENERIC_WRITE, 0,
645 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
646 if (file == INVALID_HANDLE_VALUE)
648 ERR("Could not create temp file.\n");
649 SetLastError(ERROR_OUTOFMEMORY);
650 return FALSE;
652 if (!WriteFile(file, b->pbData, b->cbData, NULL, NULL))
654 CloseHandle(file);
655 ERR("Could not write temp file.\n");
656 SetLastError(ERROR_OUTOFMEMORY);
657 return FALSE;
660 else if (dwObjectType == CERT_QUERY_OBJECT_FILE)
662 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
664 else
666 WARN("Unknown dwObjectType %lu.\n", dwObjectType);
667 SetLastError(E_INVALIDARG);
668 return FALSE;
671 if (file != INVALID_HANDLE_VALUE)
673 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
674 if (ret)
676 SIP_DISPATCH_INFO sip;
678 memset(&sip, 0, sizeof(sip));
679 sip.cbSize = sizeof(sip);
680 ret = CryptSIPLoad(&subject, 0, &sip);
681 if (ret)
683 SIP_SUBJECTINFO subjectInfo;
684 CERT_BLOB blob;
685 DWORD encodingType;
687 memset(&subjectInfo, 0, sizeof(subjectInfo));
688 subjectInfo.cbSize = sizeof(subjectInfo);
689 subjectInfo.pgSubjectType = &subject;
690 subjectInfo.hFile = file;
691 subjectInfo.pwsFileName = pvObject;
692 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
693 NULL);
694 if (ret)
696 blob.pbData = CryptMemAlloc(blob.cbData);
697 if (blob.pbData)
699 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
700 &blob.cbData, blob.pbData);
701 if (ret)
703 ret = CRYPT_QueryMessageObject(
704 CERT_QUERY_OBJECT_BLOB, &blob,
705 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
706 CERT_QUERY_FORMAT_FLAG_BINARY,
707 pdwMsgAndCertEncodingType, NULL, NULL,
708 phCertStore, phMsg);
709 if (ret && pdwContentType)
710 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
712 CryptMemFree(blob.pbData);
714 else
716 SetLastError(ERROR_OUTOFMEMORY);
717 ret = FALSE;
722 CloseHandle(file);
724 TRACE("returning %d\n", ret);
725 return ret;
728 static BOOL CRYPT_QueryPFXObject(DWORD dwObjectType, const void *pvObject,
729 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
730 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
731 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
733 CRYPT_DATA_BLOB blob = {0}, *ptr;
734 BOOL ret;
736 TRACE("(%ld, %p, %08lx, %08lx, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
737 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
738 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
739 phMsg);
741 switch (dwObjectType)
743 case CERT_QUERY_OBJECT_FILE:
744 if (!CRYPT_ReadBlobFromFile(pvObject, &blob)) return FALSE;
745 ptr = &blob;
746 break;
748 case CERT_QUERY_OBJECT_BLOB:
749 ptr = (CRYPT_DATA_BLOB *)pvObject;
750 break;
752 default:
753 return FALSE;
756 ret = PFXIsPFXBlob(ptr);
757 if (ret)
759 if (pdwMsgAndCertEncodingType) *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
760 if (pdwContentType) *pdwContentType = CERT_QUERY_CONTENT_PFX;
761 if (pdwFormatType) *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
762 if (phCertStore) *phCertStore = NULL;
763 if (phMsg) *phMsg = NULL;
766 CryptMemFree(blob.pbData);
767 return ret;
770 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
771 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
772 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
773 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
774 const void **ppvContext)
776 static const DWORD unimplementedTypes =
777 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
778 BOOL ret = TRUE;
780 TRACE("(%08lx, %p, %08lx, %08lx, %08lx, %p, %p, %p, %p, %p, %p)\n",
781 dwObjectType, pvObject, dwExpectedContentTypeFlags,
782 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
783 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
785 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
786 dwObjectType != CERT_QUERY_OBJECT_FILE)
788 WARN("unsupported type %ld\n", dwObjectType);
789 SetLastError(E_INVALIDARG);
790 return FALSE;
792 if (!pvObject)
794 WARN("missing required argument\n");
795 SetLastError(E_INVALIDARG);
796 return FALSE;
798 if (dwExpectedContentTypeFlags & unimplementedTypes)
799 WARN("unimplemented for types %08lx\n",
800 dwExpectedContentTypeFlags & unimplementedTypes);
802 if (pdwFormatType)
803 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
804 if (phCertStore)
805 *phCertStore = NULL;
806 if (phMsg)
807 *phMsg = NULL;
808 if (ppvContext)
809 *ppvContext = NULL;
811 ret = FALSE;
812 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
813 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
814 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
816 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
817 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
818 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
819 ppvContext);
821 if (!ret &&
822 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
824 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
825 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
827 if (!ret &&
828 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
829 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
830 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
832 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
833 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
834 phCertStore, ppvContext);
836 if (!ret &&
837 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
838 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
840 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
841 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
842 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
843 phCertStore, phMsg);
845 if (!ret &&
846 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
848 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
849 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
850 phCertStore, phMsg);
852 if (!ret &&
853 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PFX))
855 ret = CRYPT_QueryPFXObject(dwObjectType, pvObject,
856 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
857 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
858 phCertStore, phMsg);
860 if (!ret)
861 SetLastError(CRYPT_E_NO_MATCH);
862 TRACE("returning %d\n", ret);
863 return ret;
866 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
867 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
868 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
869 DWORD *pcbFormat)
871 BOOL ret;
872 DWORD bytesNeeded;
874 if (cbEncoded)
875 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
876 else
877 bytesNeeded = sizeof(WCHAR);
878 if (!pbFormat)
880 *pcbFormat = bytesNeeded;
881 ret = TRUE;
883 else if (*pcbFormat < bytesNeeded)
885 *pcbFormat = bytesNeeded;
886 SetLastError(ERROR_MORE_DATA);
887 ret = FALSE;
889 else
891 DWORD i;
892 LPWSTR ptr = pbFormat;
894 *pcbFormat = bytesNeeded;
895 if (cbEncoded)
897 for (i = 0; i < cbEncoded; i++)
899 if (i < cbEncoded - 1)
900 ptr += swprintf(ptr, 4, L"%02x ", pbEncoded[i]);
901 else
902 ptr += swprintf(ptr, 3, L"%02x", pbEncoded[i]);
905 else
906 *ptr = 0;
907 ret = TRUE;
909 return ret;
912 #define MAX_STRING_RESOURCE_LEN 128
914 static const WCHAR commaSpace[] = L", ";
916 struct BitToString
918 BYTE bit;
919 int id;
920 WCHAR str[MAX_STRING_RESOURCE_LEN];
923 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
924 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
926 DWORD bytesNeeded = sizeof(WCHAR);
927 unsigned int i;
928 BOOL ret = TRUE, localFirst = *first;
930 for (i = 0; i < mapEntries; i++)
931 if (bits & map[i].bit)
933 if (!localFirst)
934 bytesNeeded += lstrlenW(commaSpace) * sizeof(WCHAR);
935 localFirst = FALSE;
936 bytesNeeded += lstrlenW(map[i].str) * sizeof(WCHAR);
938 if (!pbFormat)
940 *first = localFirst;
941 *pcbFormat = bytesNeeded;
943 else if (*pcbFormat < bytesNeeded)
945 *first = localFirst;
946 *pcbFormat = bytesNeeded;
947 SetLastError(ERROR_MORE_DATA);
948 ret = FALSE;
950 else
952 LPWSTR str = pbFormat;
954 localFirst = *first;
955 *pcbFormat = bytesNeeded;
956 for (i = 0; i < mapEntries; i++)
957 if (bits & map[i].bit)
959 if (!localFirst)
961 lstrcpyW(str, commaSpace);
962 str += lstrlenW(commaSpace);
964 localFirst = FALSE;
965 lstrcpyW(str, map[i].str);
966 str += lstrlenW(map[i].str);
968 *first = localFirst;
970 return ret;
973 static struct BitToString keyUsageByte0Map[] = {
974 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
975 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
976 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
977 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
978 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
979 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
980 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
981 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
982 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
984 static struct BitToString keyUsageByte1Map[] = {
985 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
988 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
989 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
990 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
991 DWORD *pcbFormat)
993 DWORD size;
994 CRYPT_BIT_BLOB *bits;
995 BOOL ret;
997 if (!cbEncoded)
999 SetLastError(E_INVALIDARG);
1000 return FALSE;
1002 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
1003 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
1005 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1006 DWORD bytesNeeded = sizeof(WCHAR);
1008 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
1009 if (!bits->cbData || bits->cbData > 2)
1011 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
1012 if (!pbFormat)
1013 *pcbFormat = bytesNeeded;
1014 else if (*pcbFormat < bytesNeeded)
1016 *pcbFormat = bytesNeeded;
1017 SetLastError(ERROR_MORE_DATA);
1018 ret = FALSE;
1020 else
1022 LPWSTR str = pbFormat;
1024 *pcbFormat = bytesNeeded;
1025 lstrcpyW(str, infoNotAvailable);
1028 else
1030 static BOOL stringsLoaded = FALSE;
1031 unsigned int i;
1032 DWORD bitStringLen;
1033 BOOL first = TRUE;
1035 if (!stringsLoaded)
1037 for (i = 0; i < ARRAY_SIZE(keyUsageByte0Map); i++)
1038 LoadStringW(hInstance, keyUsageByte0Map[i].id, keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
1039 for (i = 0; i < ARRAY_SIZE(keyUsageByte1Map); i++)
1040 LoadStringW(hInstance, keyUsageByte1Map[i].id, keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
1041 stringsLoaded = TRUE;
1043 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, ARRAY_SIZE(keyUsageByte0Map),
1044 NULL, &bitStringLen, &first);
1045 bytesNeeded += bitStringLen;
1046 if (bits->cbData == 2)
1048 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, ARRAY_SIZE(keyUsageByte1Map),
1049 NULL, &bitStringLen, &first);
1050 bytesNeeded += bitStringLen;
1052 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
1053 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1054 bits->cbData, NULL, &size);
1055 bytesNeeded += size;
1056 if (!pbFormat)
1057 *pcbFormat = bytesNeeded;
1058 else if (*pcbFormat < bytesNeeded)
1060 *pcbFormat = bytesNeeded;
1061 SetLastError(ERROR_MORE_DATA);
1062 ret = FALSE;
1064 else
1066 LPWSTR str = pbFormat;
1068 bitStringLen = bytesNeeded;
1069 first = TRUE;
1070 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, ARRAY_SIZE(keyUsageByte0Map),
1071 str, &bitStringLen, &first);
1072 str += bitStringLen / sizeof(WCHAR) - 1;
1073 if (bits->cbData == 2)
1075 bitStringLen = bytesNeeded;
1076 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, ARRAY_SIZE(keyUsageByte1Map),
1077 str, &bitStringLen, &first);
1078 str += bitStringLen / sizeof(WCHAR) - 1;
1080 *str++ = ' ';
1081 *str++ = '(';
1082 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1083 bits->cbData, str, &size);
1084 str += size / sizeof(WCHAR) - 1;
1085 *str++ = ')';
1086 *str = 0;
1089 LocalFree(bits);
1091 return ret;
1094 static const WCHAR crlf[] = L"\r\n";
1096 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1097 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1098 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1099 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1101 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1102 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1103 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1104 DWORD *pcbFormat)
1106 DWORD size;
1107 CERT_BASIC_CONSTRAINTS2_INFO *info;
1108 BOOL ret;
1110 if (!cbEncoded)
1112 SetLastError(E_INVALIDARG);
1113 return FALSE;
1115 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1116 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1118 static BOOL stringsLoaded = FALSE;
1119 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1120 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1121 LPCWSTR sep, subjectType;
1122 DWORD sepLen;
1124 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1126 sep = crlf;
1127 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
1129 else
1131 sep = commaSpace;
1132 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
1135 if (!stringsLoaded)
1137 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader, ARRAY_SIZE(subjectTypeHeader));
1138 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA, ARRAY_SIZE(subjectTypeCA));
1139 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT, subjectTypeEndCert, ARRAY_SIZE(subjectTypeEndCert));
1140 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader, ARRAY_SIZE(pathLengthHeader));
1141 stringsLoaded = TRUE;
1143 bytesNeeded += lstrlenW(subjectTypeHeader) * sizeof(WCHAR);
1144 if (info->fCA)
1145 subjectType = subjectTypeCA;
1146 else
1147 subjectType = subjectTypeEndCert;
1148 bytesNeeded += lstrlenW(subjectType) * sizeof(WCHAR);
1149 bytesNeeded += sepLen;
1150 bytesNeeded += lstrlenW(pathLengthHeader) * sizeof(WCHAR);
1151 if (info->fPathLenConstraint)
1152 swprintf(pathLength, ARRAY_SIZE(pathLength), L"%d", info->dwPathLenConstraint);
1153 else
1154 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength, ARRAY_SIZE(pathLength));
1155 bytesNeeded += lstrlenW(pathLength) * sizeof(WCHAR);
1156 if (!pbFormat)
1157 *pcbFormat = bytesNeeded;
1158 else if (*pcbFormat < bytesNeeded)
1160 *pcbFormat = bytesNeeded;
1161 SetLastError(ERROR_MORE_DATA);
1162 ret = FALSE;
1164 else
1166 LPWSTR str = pbFormat;
1168 *pcbFormat = bytesNeeded;
1169 lstrcpyW(str, subjectTypeHeader);
1170 str += lstrlenW(subjectTypeHeader);
1171 lstrcpyW(str, subjectType);
1172 str += lstrlenW(subjectType);
1173 lstrcpyW(str, sep);
1174 str += sepLen / sizeof(WCHAR);
1175 lstrcpyW(str, pathLengthHeader);
1176 str += lstrlenW(pathLengthHeader);
1177 lstrcpyW(str, pathLength);
1179 LocalFree(info);
1181 return ret;
1184 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1185 LPWSTR str, DWORD *pcbStr)
1187 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1188 DWORD bytesNeeded;
1189 BOOL ret;
1191 LoadStringW(hInstance, id, buf, ARRAY_SIZE(buf));
1192 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1193 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1194 bytesNeeded += lstrlenW(buf) * sizeof(WCHAR);
1195 if (!str)
1197 *pcbStr = bytesNeeded;
1198 ret = TRUE;
1200 else if (*pcbStr < bytesNeeded)
1202 *pcbStr = bytesNeeded;
1203 SetLastError(ERROR_MORE_DATA);
1204 ret = FALSE;
1206 else
1208 *pcbStr = bytesNeeded;
1209 lstrcpyW(str, buf);
1210 str += lstrlenW(str);
1211 bytesNeeded -= lstrlenW(str) * sizeof(WCHAR);
1212 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1213 blob->pbData, blob->cbData, str, &bytesNeeded);
1215 return ret;
1218 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1219 DWORD *pcbStr)
1221 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1224 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1225 DWORD *pcbStr)
1227 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1228 str, pcbStr);
1231 static const WCHAR indent[] = L" ";
1232 static const WCHAR colonCrlf[] = L":\r\n";
1234 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1235 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1237 BOOL ret;
1238 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1239 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1240 WCHAR ipAddrBuf[32];
1241 WCHAR maskBuf[16];
1242 DWORD bytesNeeded = sizeof(WCHAR);
1243 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1245 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1246 bytesNeeded += indentLevel * lstrlenW(indent) * sizeof(WCHAR);
1247 switch (entry->dwAltNameChoice)
1249 case CERT_ALT_NAME_RFC822_NAME:
1250 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf, ARRAY_SIZE(buf));
1251 bytesNeeded += lstrlenW(entry->pwszRfc822Name) * sizeof(WCHAR);
1252 ret = TRUE;
1253 break;
1254 case CERT_ALT_NAME_DNS_NAME:
1255 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf, ARRAY_SIZE(buf));
1256 bytesNeeded += lstrlenW(entry->pwszDNSName) * sizeof(WCHAR);
1257 ret = TRUE;
1258 break;
1259 case CERT_ALT_NAME_DIRECTORY_NAME:
1261 DWORD directoryNameLen;
1263 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1264 strType |= CERT_NAME_STR_CRLF_FLAG;
1265 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1266 indentLevel + 1, &entry->DirectoryName, strType, NULL, 0);
1267 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf, ARRAY_SIZE(buf));
1268 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1269 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1270 bytesNeeded += lstrlenW(colonCrlf) * sizeof(WCHAR);
1271 else
1272 bytesNeeded += sizeof(WCHAR); /* '=' */
1273 ret = TRUE;
1274 break;
1276 case CERT_ALT_NAME_URL:
1277 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf, ARRAY_SIZE(buf));
1278 bytesNeeded += lstrlenW(entry->pwszURL) * sizeof(WCHAR);
1279 ret = TRUE;
1280 break;
1281 case CERT_ALT_NAME_IP_ADDRESS:
1283 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf, ARRAY_SIZE(buf));
1284 if (entry->IPAddress.cbData == 8)
1286 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1288 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask, ARRAY_SIZE(mask));
1289 bytesNeeded += lstrlenW(mask) * sizeof(WCHAR);
1290 swprintf(ipAddrBuf, ARRAY_SIZE(ipAddrBuf), L"%d.%d.%d.%d",
1291 entry->IPAddress.pbData[0],
1292 entry->IPAddress.pbData[1],
1293 entry->IPAddress.pbData[2],
1294 entry->IPAddress.pbData[3]);
1295 bytesNeeded += lstrlenW(ipAddrBuf) * sizeof(WCHAR);
1296 /* indent again, for the mask line */
1297 bytesNeeded += indentLevel * lstrlenW(indent) * sizeof(WCHAR);
1298 swprintf(maskBuf, ARRAY_SIZE(maskBuf), L"%d.%d.%d.%d",
1299 entry->IPAddress.pbData[4],
1300 entry->IPAddress.pbData[5],
1301 entry->IPAddress.pbData[6],
1302 entry->IPAddress.pbData[7]);
1303 bytesNeeded += lstrlenW(maskBuf) * sizeof(WCHAR);
1304 bytesNeeded += lstrlenW(crlf) * sizeof(WCHAR);
1306 else
1308 swprintf(ipAddrBuf, ARRAY_SIZE(ipAddrBuf), L"%d.%d.%d.%d/%d.%d.%d.%d",
1309 entry->IPAddress.pbData[0],
1310 entry->IPAddress.pbData[1],
1311 entry->IPAddress.pbData[2],
1312 entry->IPAddress.pbData[3],
1313 entry->IPAddress.pbData[4],
1314 entry->IPAddress.pbData[5],
1315 entry->IPAddress.pbData[6],
1316 entry->IPAddress.pbData[7]);
1317 bytesNeeded += (lstrlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1319 ret = TRUE;
1321 else
1323 FIXME("unknown IP address format (%ld bytes)\n",
1324 entry->IPAddress.cbData);
1325 ret = FALSE;
1327 break;
1329 default:
1330 FIXME("unimplemented for %ld\n", entry->dwAltNameChoice);
1331 ret = FALSE;
1333 if (ret)
1335 bytesNeeded += lstrlenW(buf) * sizeof(WCHAR);
1336 if (!str)
1337 *pcbStr = bytesNeeded;
1338 else if (*pcbStr < bytesNeeded)
1340 *pcbStr = bytesNeeded;
1341 SetLastError(ERROR_MORE_DATA);
1342 ret = FALSE;
1344 else
1346 DWORD i;
1348 *pcbStr = bytesNeeded;
1349 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1351 for (i = 0; i < indentLevel; i++)
1353 lstrcpyW(str, indent);
1354 str += lstrlenW(indent);
1357 lstrcpyW(str, buf);
1358 str += lstrlenW(str);
1359 switch (entry->dwAltNameChoice)
1361 case CERT_ALT_NAME_RFC822_NAME:
1362 case CERT_ALT_NAME_DNS_NAME:
1363 case CERT_ALT_NAME_URL:
1364 lstrcpyW(str, entry->pwszURL);
1365 break;
1366 case CERT_ALT_NAME_DIRECTORY_NAME:
1367 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1369 lstrcpyW(str, colonCrlf);
1370 str += lstrlenW(colonCrlf);
1372 else
1373 *str++ = '=';
1374 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1375 indentLevel + 1, &entry->DirectoryName, strType, str,
1376 bytesNeeded / sizeof(WCHAR));
1377 break;
1378 case CERT_ALT_NAME_IP_ADDRESS:
1379 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1381 lstrcpyW(str, ipAddrBuf);
1382 str += lstrlenW(ipAddrBuf);
1383 lstrcpyW(str, crlf);
1384 str += lstrlenW(crlf);
1385 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1387 for (i = 0; i < indentLevel; i++)
1389 lstrcpyW(str, indent);
1390 str += lstrlenW(indent);
1393 lstrcpyW(str, mask);
1394 str += lstrlenW(mask);
1395 lstrcpyW(str, maskBuf);
1397 else
1398 lstrcpyW(str, ipAddrBuf);
1399 break;
1403 return ret;
1406 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1407 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1409 DWORD i, size, bytesNeeded = 0;
1410 BOOL ret = TRUE;
1411 LPCWSTR sep;
1412 DWORD sepLen;
1414 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1416 sep = crlf;
1417 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
1419 else
1421 sep = commaSpace;
1422 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
1425 for (i = 0; ret && i < name->cAltEntry; i++)
1427 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1428 &name->rgAltEntry[i], NULL, &size);
1429 if (ret)
1431 bytesNeeded += size - sizeof(WCHAR);
1432 if (i < name->cAltEntry - 1)
1433 bytesNeeded += sepLen;
1436 if (ret)
1438 bytesNeeded += sizeof(WCHAR);
1439 if (!str)
1440 *pcbStr = bytesNeeded;
1441 else if (*pcbStr < bytesNeeded)
1443 *pcbStr = bytesNeeded;
1444 SetLastError(ERROR_MORE_DATA);
1445 ret = FALSE;
1447 else
1449 *pcbStr = bytesNeeded;
1450 for (i = 0; ret && i < name->cAltEntry; i++)
1452 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1453 &name->rgAltEntry[i], str, &size);
1454 if (ret)
1456 str += size / sizeof(WCHAR) - 1;
1457 if (i < name->cAltEntry - 1)
1459 lstrcpyW(str, sep);
1460 str += sepLen / sizeof(WCHAR);
1466 return ret;
1469 static const WCHAR colonSep[] = L": ";
1471 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1472 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1473 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1474 DWORD *pcbFormat)
1476 BOOL ret;
1477 CERT_ALT_NAME_INFO *info;
1478 DWORD size;
1480 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1481 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1483 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1484 LocalFree(info);
1486 return ret;
1489 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1490 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1492 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1493 DWORD bytesNeeded, sepLen;
1494 LPCWSTR sep;
1495 BOOL ret;
1497 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, ARRAY_SIZE(buf));
1498 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1499 &bytesNeeded);
1500 bytesNeeded += lstrlenW(buf) * sizeof(WCHAR);
1501 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1503 sep = colonCrlf;
1504 sepLen = lstrlenW(colonCrlf) * sizeof(WCHAR);
1506 else
1508 sep = colonSep;
1509 sepLen = lstrlenW(colonSep) * sizeof(WCHAR);
1511 bytesNeeded += sepLen;
1512 if (ret)
1514 if (!str)
1515 *pcbStr = bytesNeeded;
1516 else if (*pcbStr < bytesNeeded)
1518 *pcbStr = bytesNeeded;
1519 SetLastError(ERROR_MORE_DATA);
1520 ret = FALSE;
1522 else
1524 *pcbStr = bytesNeeded;
1525 lstrcpyW(str, buf);
1526 bytesNeeded -= lstrlenW(str) * sizeof(WCHAR);
1527 str += lstrlenW(str);
1528 lstrcpyW(str, sep);
1529 str += sepLen / sizeof(WCHAR);
1530 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1531 &bytesNeeded);
1534 return ret;
1537 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1538 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1539 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1540 DWORD *pcbFormat)
1542 CERT_AUTHORITY_KEY_ID2_INFO *info;
1543 DWORD size;
1544 BOOL ret = FALSE;
1546 if (!cbEncoded)
1548 SetLastError(E_INVALIDARG);
1549 return FALSE;
1551 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1552 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1554 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1555 LPCWSTR sep;
1556 DWORD sepLen;
1557 BOOL needSeparator = FALSE;
1559 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1561 sep = crlf;
1562 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
1564 else
1566 sep = commaSpace;
1567 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
1570 if (info->KeyId.cbData)
1572 needSeparator = TRUE;
1573 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1574 if (ret)
1576 /* don't include NULL-terminator more than once */
1577 bytesNeeded += size - sizeof(WCHAR);
1580 if (info->AuthorityCertIssuer.cAltEntry)
1582 if (needSeparator)
1583 bytesNeeded += sepLen;
1584 needSeparator = TRUE;
1585 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1586 &info->AuthorityCertIssuer, NULL, &size);
1587 if (ret)
1589 /* don't include NULL-terminator more than once */
1590 bytesNeeded += size - sizeof(WCHAR);
1593 if (info->AuthorityCertSerialNumber.cbData)
1595 if (needSeparator)
1596 bytesNeeded += sepLen;
1597 ret = CRYPT_FormatCertSerialNumber(
1598 &info->AuthorityCertSerialNumber, NULL, &size);
1599 if (ret)
1601 /* don't include NULL-terminator more than once */
1602 bytesNeeded += size - sizeof(WCHAR);
1605 if (ret)
1607 if (!pbFormat)
1608 *pcbFormat = bytesNeeded;
1609 else if (*pcbFormat < bytesNeeded)
1611 *pcbFormat = bytesNeeded;
1612 SetLastError(ERROR_MORE_DATA);
1613 ret = FALSE;
1615 else
1617 LPWSTR str = pbFormat;
1619 *pcbFormat = bytesNeeded;
1620 needSeparator = FALSE;
1621 if (info->KeyId.cbData)
1623 needSeparator = TRUE;
1624 /* Overestimate size available, it's already been checked
1625 * above.
1627 size = bytesNeeded;
1628 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1629 if (ret)
1630 str += size / sizeof(WCHAR) - 1;
1632 if (info->AuthorityCertIssuer.cAltEntry)
1634 if (needSeparator)
1636 lstrcpyW(str, sep);
1637 str += sepLen / sizeof(WCHAR);
1639 needSeparator = TRUE;
1640 /* Overestimate size available, it's already been checked
1641 * above.
1643 size = bytesNeeded;
1644 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1645 &info->AuthorityCertIssuer, str, &size);
1646 if (ret)
1647 str += size / sizeof(WCHAR) - 1;
1649 if (info->AuthorityCertSerialNumber.cbData)
1651 if (needSeparator)
1653 lstrcpyW(str, sep);
1654 str += sepLen / sizeof(WCHAR);
1656 /* Overestimate size available, it's already been checked
1657 * above.
1659 size = bytesNeeded;
1660 ret = CRYPT_FormatCertSerialNumber(
1661 &info->AuthorityCertSerialNumber, str, &size);
1665 LocalFree(info);
1667 return ret;
1670 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1671 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1672 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1673 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1674 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1675 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1677 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1678 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1679 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1680 DWORD *pcbFormat)
1682 CERT_AUTHORITY_INFO_ACCESS *info;
1683 DWORD size;
1684 BOOL ret = FALSE;
1686 if (!cbEncoded)
1688 SetLastError(E_INVALIDARG);
1689 return FALSE;
1691 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1692 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1693 NULL, &info, &size)))
1695 DWORD bytesNeeded = sizeof(WCHAR);
1697 if (!info->cAccDescr)
1699 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1701 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
1702 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
1703 if (!pbFormat)
1704 *pcbFormat = bytesNeeded;
1705 else if (*pcbFormat < bytesNeeded)
1707 *pcbFormat = bytesNeeded;
1708 SetLastError(ERROR_MORE_DATA);
1709 ret = FALSE;
1711 else
1713 *pcbFormat = bytesNeeded;
1714 lstrcpyW(pbFormat, infoNotAvailable);
1717 else
1719 static const WCHAR equal[] = L"=";
1720 static BOOL stringsLoaded = FALSE;
1721 DWORD i;
1722 LPCWSTR headingSep, accessMethodSep, locationSep;
1723 WCHAR accessDescrNum[11];
1725 if (!stringsLoaded)
1727 LoadStringW(hInstance, IDS_AIA, aia, ARRAY_SIZE(aia));
1728 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod, ARRAY_SIZE(accessMethod));
1729 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp, ARRAY_SIZE(ocsp));
1730 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers, ARRAY_SIZE(caIssuers));
1731 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown, ARRAY_SIZE(unknown));
1732 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation, ARRAY_SIZE(accessLocation));
1733 stringsLoaded = TRUE;
1735 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1737 headingSep = crlf;
1738 accessMethodSep = crlf;
1739 locationSep = colonCrlf;
1741 else
1743 headingSep = colonSep;
1744 accessMethodSep = commaSpace;
1745 locationSep = equal;
1748 for (i = 0; ret && i < info->cAccDescr; i++)
1750 /* Heading */
1751 bytesNeeded += sizeof(WCHAR); /* left bracket */
1752 swprintf(accessDescrNum, ARRAY_SIZE(accessDescrNum), L"%d", i + 1);
1753 bytesNeeded += lstrlenW(accessDescrNum) * sizeof(WCHAR);
1754 bytesNeeded += sizeof(WCHAR); /* right bracket */
1755 bytesNeeded += lstrlenW(aia) * sizeof(WCHAR);
1756 bytesNeeded += lstrlenW(headingSep) * sizeof(WCHAR);
1757 /* Access method */
1758 bytesNeeded += lstrlenW(accessMethod) * sizeof(WCHAR);
1759 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1760 bytesNeeded += lstrlenW(indent) * sizeof(WCHAR);
1761 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1762 szOID_PKIX_OCSP))
1763 bytesNeeded += lstrlenW(ocsp) * sizeof(WCHAR);
1764 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1765 szOID_PKIX_CA_ISSUERS))
1766 bytesNeeded += lstrlenW(caIssuers) * sizeof(caIssuers);
1767 else
1768 bytesNeeded += lstrlenW(unknown) * sizeof(WCHAR);
1769 bytesNeeded += sizeof(WCHAR); /* space */
1770 bytesNeeded += sizeof(WCHAR); /* left paren */
1771 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1772 * sizeof(WCHAR);
1773 bytesNeeded += sizeof(WCHAR); /* right paren */
1774 /* Delimiter between access method and location */
1775 bytesNeeded += lstrlenW(accessMethodSep) * sizeof(WCHAR);
1776 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1777 bytesNeeded += lstrlenW(indent) * sizeof(WCHAR);
1778 bytesNeeded += lstrlenW(accessLocation) * sizeof(WCHAR);
1779 bytesNeeded += lstrlenW(locationSep) * sizeof(WCHAR);
1780 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1781 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1782 if (ret)
1783 bytesNeeded += size - sizeof(WCHAR);
1784 /* Need extra delimiter between access method entries */
1785 if (i < info->cAccDescr - 1)
1786 bytesNeeded += lstrlenW(accessMethodSep) * sizeof(WCHAR);
1788 if (ret)
1790 if (!pbFormat)
1791 *pcbFormat = bytesNeeded;
1792 else if (*pcbFormat < bytesNeeded)
1794 *pcbFormat = bytesNeeded;
1795 SetLastError(ERROR_MORE_DATA);
1796 ret = FALSE;
1798 else
1800 LPWSTR str = pbFormat;
1801 DWORD altNameEntrySize;
1803 *pcbFormat = bytesNeeded;
1804 for (i = 0; ret && i < info->cAccDescr; i++)
1806 LPCSTR oidPtr;
1808 *str++ = '[';
1809 swprintf(accessDescrNum, ARRAY_SIZE(accessDescrNum), L"%d", i + 1);
1810 lstrcpyW(str, accessDescrNum);
1811 str += lstrlenW(accessDescrNum);
1812 *str++ = ']';
1813 lstrcpyW(str, aia);
1814 str += lstrlenW(aia);
1815 lstrcpyW(str, headingSep);
1816 str += lstrlenW(headingSep);
1817 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1819 lstrcpyW(str, indent);
1820 str += lstrlenW(indent);
1822 lstrcpyW(str, accessMethod);
1823 str += lstrlenW(accessMethod);
1824 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1825 szOID_PKIX_OCSP))
1827 lstrcpyW(str, ocsp);
1828 str += lstrlenW(ocsp);
1830 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1831 szOID_PKIX_CA_ISSUERS))
1833 lstrcpyW(str, caIssuers);
1834 str += lstrlenW(caIssuers);
1836 else
1838 lstrcpyW(str, unknown);
1839 str += lstrlenW(unknown);
1841 *str++ = ' ';
1842 *str++ = '(';
1843 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1844 *oidPtr; oidPtr++, str++)
1845 *str = *oidPtr;
1846 *str++ = ')';
1847 lstrcpyW(str, accessMethodSep);
1848 str += lstrlenW(accessMethodSep);
1849 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1851 lstrcpyW(str, indent);
1852 str += lstrlenW(indent);
1854 lstrcpyW(str, accessLocation);
1855 str += lstrlenW(accessLocation);
1856 lstrcpyW(str, locationSep);
1857 str += lstrlenW(locationSep);
1858 /* This overestimates the size available, but that
1859 * won't matter since we checked earlier whether enough
1860 * space for the entire string was available.
1862 altNameEntrySize = bytesNeeded;
1863 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1864 &info->rgAccDescr[i].AccessLocation, str,
1865 &altNameEntrySize);
1866 if (ret)
1867 str += altNameEntrySize / sizeof(WCHAR) - 1;
1868 if (i < info->cAccDescr - 1)
1870 lstrcpyW(str, accessMethodSep);
1871 str += lstrlenW(accessMethodSep);
1877 LocalFree(info);
1879 return ret;
1882 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1883 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1884 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1885 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1886 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1887 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1889 struct reason_map_entry
1891 BYTE reasonBit;
1892 LPWSTR reason;
1893 int id;
1895 static struct reason_map_entry reason_map[] = {
1896 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1897 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1898 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1899 IDS_REASON_AFFILIATION_CHANGED },
1900 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1901 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1902 IDS_REASON_CESSATION_OF_OPERATION },
1903 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1904 IDS_REASON_CERTIFICATE_HOLD },
1907 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1908 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1910 static const WCHAR sep[] = L", ";
1911 static BOOL stringsLoaded = FALSE;
1912 unsigned int i, numReasons = 0;
1913 BOOL ret = TRUE;
1914 DWORD bytesNeeded = sizeof(WCHAR);
1915 WCHAR bits[6];
1917 if (!stringsLoaded)
1919 for (i = 0; i < ARRAY_SIZE(reason_map); i++)
1920 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1921 MAX_STRING_RESOURCE_LEN);
1922 stringsLoaded = TRUE;
1924 /* No need to check reasonFlags->cbData, we already know it's positive.
1925 * Ignore any other bytes, as they're for undefined bits.
1927 for (i = 0; i < ARRAY_SIZE(reason_map); i++)
1929 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1931 bytesNeeded += lstrlenW(reason_map[i].reason) * sizeof(WCHAR);
1932 if (numReasons++)
1933 bytesNeeded += lstrlenW(sep) * sizeof(WCHAR);
1936 swprintf(bits, ARRAY_SIZE(bits), L" (%02x)", reasonFlags->pbData[0]);
1937 bytesNeeded += lstrlenW(bits);
1938 if (!str)
1939 *pcbStr = bytesNeeded;
1940 else if (*pcbStr < bytesNeeded)
1942 *pcbStr = bytesNeeded;
1943 SetLastError(ERROR_MORE_DATA);
1944 ret = FALSE;
1946 else
1948 *pcbStr = bytesNeeded;
1949 for (i = 0; i < ARRAY_SIZE(reason_map); i++)
1951 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1953 lstrcpyW(str, reason_map[i].reason);
1954 str += lstrlenW(reason_map[i].reason);
1955 if (i < ARRAY_SIZE(reason_map) - 1 && numReasons)
1957 lstrcpyW(str, sep);
1958 str += lstrlenW(sep);
1962 lstrcpyW(str, bits);
1964 return ret;
1967 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1968 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1969 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1970 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1971 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1972 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1974 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1975 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1976 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1977 DWORD *pcbFormat)
1979 CRL_DIST_POINTS_INFO *info;
1980 DWORD size;
1981 BOOL ret = FALSE;
1983 if (!cbEncoded)
1985 SetLastError(E_INVALIDARG);
1986 return FALSE;
1988 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1989 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1991 static const WCHAR colon[] = L":";
1992 static BOOL stringsLoaded = FALSE;
1993 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1994 BOOL haveAnEntry = FALSE;
1995 LPCWSTR headingSep, nameSep;
1996 WCHAR distPointNum[11];
1997 DWORD i;
1999 if (!stringsLoaded)
2001 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint, ARRAY_SIZE(crlDistPoint));
2002 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName, ARRAY_SIZE(distPointName));
2003 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName, ARRAY_SIZE(fullName));
2004 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName, ARRAY_SIZE(rdnName));
2005 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason, ARRAY_SIZE(reason));
2006 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer, ARRAY_SIZE(issuer));
2007 stringsLoaded = TRUE;
2009 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2011 headingSep = crlf;
2012 nameSep = colonCrlf;
2014 else
2016 headingSep = colonSep;
2017 nameSep = colon;
2020 for (i = 0; ret && i < info->cDistPoint; i++)
2022 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2024 if (distPoint->DistPointName.dwDistPointNameChoice !=
2025 CRL_DIST_POINT_NO_NAME)
2027 bytesNeeded += lstrlenW(distPointName) * sizeof(WCHAR);
2028 bytesNeeded += lstrlenW(nameSep) * sizeof(WCHAR);
2029 if (distPoint->DistPointName.dwDistPointNameChoice ==
2030 CRL_DIST_POINT_FULL_NAME)
2031 bytesNeeded += lstrlenW(fullName) * sizeof(WCHAR);
2032 else
2033 bytesNeeded += lstrlenW(rdnName) * sizeof(WCHAR);
2034 bytesNeeded += lstrlenW(nameSep) * sizeof(WCHAR);
2035 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2036 bytesNeeded += 2 * lstrlenW(indent) * sizeof(WCHAR);
2037 /* The indent level (3) is higher than when used as the issuer,
2038 * because the name is subordinate to the name type (full vs.
2039 * RDN.)
2041 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2042 &distPoint->DistPointName.FullName, NULL, &size);
2043 if (ret)
2044 bytesNeeded += size - sizeof(WCHAR);
2045 haveAnEntry = TRUE;
2047 else if (distPoint->ReasonFlags.cbData)
2049 bytesNeeded += lstrlenW(reason) * sizeof(WCHAR);
2050 ret = CRYPT_FormatReason(dwFormatStrType,
2051 &distPoint->ReasonFlags, NULL, &size);
2052 if (ret)
2053 bytesNeeded += size - sizeof(WCHAR);
2054 haveAnEntry = TRUE;
2056 else if (distPoint->CRLIssuer.cAltEntry)
2058 bytesNeeded += lstrlenW(issuer) * sizeof(WCHAR);
2059 bytesNeeded += lstrlenW(nameSep) * sizeof(WCHAR);
2060 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2061 &distPoint->CRLIssuer, NULL, &size);
2062 if (ret)
2063 bytesNeeded += size - sizeof(WCHAR);
2064 haveAnEntry = TRUE;
2066 if (haveAnEntry)
2068 bytesNeeded += sizeof(WCHAR); /* left bracket */
2069 swprintf(distPointNum, ARRAY_SIZE(distPointNum), L"%d", i + 1);
2070 bytesNeeded += lstrlenW(distPointNum) * sizeof(WCHAR);
2071 bytesNeeded += sizeof(WCHAR); /* right bracket */
2072 bytesNeeded += lstrlenW(crlDistPoint) * sizeof(WCHAR);
2073 bytesNeeded += lstrlenW(headingSep) * sizeof(WCHAR);
2074 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2075 bytesNeeded += lstrlenW(indent) * sizeof(WCHAR);
2078 if (!haveAnEntry)
2080 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2082 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
2083 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
2084 if (!pbFormat)
2085 *pcbFormat = bytesNeeded;
2086 else if (*pcbFormat < bytesNeeded)
2088 *pcbFormat = bytesNeeded;
2089 SetLastError(ERROR_MORE_DATA);
2090 ret = FALSE;
2092 else
2094 *pcbFormat = bytesNeeded;
2095 lstrcpyW(pbFormat, infoNotAvailable);
2098 else
2100 if (!pbFormat)
2101 *pcbFormat = bytesNeeded;
2102 else if (*pcbFormat < bytesNeeded)
2104 *pcbFormat = bytesNeeded;
2105 SetLastError(ERROR_MORE_DATA);
2106 ret = FALSE;
2108 else
2110 LPWSTR str = pbFormat;
2112 *pcbFormat = bytesNeeded;
2113 for (i = 0; ret && i < info->cDistPoint; i++)
2115 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2117 *str++ = '[';
2118 swprintf(distPointNum, ARRAY_SIZE(distPointNum), L"%d", i + 1);
2119 lstrcpyW(str, distPointNum);
2120 str += lstrlenW(distPointNum);
2121 *str++ = ']';
2122 lstrcpyW(str, crlDistPoint);
2123 str += lstrlenW(crlDistPoint);
2124 lstrcpyW(str, headingSep);
2125 str += lstrlenW(headingSep);
2126 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2128 lstrcpyW(str, indent);
2129 str += lstrlenW(indent);
2131 if (distPoint->DistPointName.dwDistPointNameChoice !=
2132 CRL_DIST_POINT_NO_NAME)
2134 DWORD altNameSize = bytesNeeded;
2136 lstrcpyW(str, distPointName);
2137 str += lstrlenW(distPointName);
2138 lstrcpyW(str, nameSep);
2139 str += lstrlenW(nameSep);
2140 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2142 lstrcpyW(str, indent);
2143 str += lstrlenW(indent);
2144 lstrcpyW(str, indent);
2145 str += lstrlenW(indent);
2147 if (distPoint->DistPointName.dwDistPointNameChoice ==
2148 CRL_DIST_POINT_FULL_NAME)
2150 lstrcpyW(str, fullName);
2151 str += lstrlenW(fullName);
2153 else
2155 lstrcpyW(str, rdnName);
2156 str += lstrlenW(rdnName);
2158 lstrcpyW(str, nameSep);
2159 str += lstrlenW(nameSep);
2160 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2161 &distPoint->DistPointName.FullName, str,
2162 &altNameSize);
2163 if (ret)
2164 str += altNameSize / sizeof(WCHAR) - 1;
2166 else if (distPoint->ReasonFlags.cbData)
2168 DWORD reasonSize = bytesNeeded;
2170 lstrcpyW(str, reason);
2171 str += lstrlenW(reason);
2172 ret = CRYPT_FormatReason(dwFormatStrType,
2173 &distPoint->ReasonFlags, str, &reasonSize);
2174 if (ret)
2175 str += reasonSize / sizeof(WCHAR) - 1;
2177 else if (distPoint->CRLIssuer.cAltEntry)
2179 DWORD crlIssuerSize = bytesNeeded;
2181 lstrcpyW(str, issuer);
2182 str += lstrlenW(issuer);
2183 lstrcpyW(str, nameSep);
2184 str += lstrlenW(nameSep);
2185 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2186 &distPoint->CRLIssuer, str,
2187 &crlIssuerSize);
2188 if (ret)
2189 str += crlIssuerSize / sizeof(WCHAR) - 1;
2194 LocalFree(info);
2196 return ret;
2199 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2200 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2201 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2202 DWORD *pcbFormat)
2204 CERT_ENHKEY_USAGE *usage;
2205 DWORD size;
2206 BOOL ret = FALSE;
2208 if (!cbEncoded)
2210 SetLastError(E_INVALIDARG);
2211 return FALSE;
2213 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2214 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2216 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2217 DWORD i;
2218 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2219 LPCWSTR sep;
2220 DWORD sepLen;
2222 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2224 sep = crlf;
2225 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
2227 else
2229 sep = commaSpace;
2230 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
2233 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown, ARRAY_SIZE(unknown));
2234 for (i = 0; i < usage->cUsageIdentifier; i++)
2236 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2237 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2239 if (info)
2240 bytesNeeded += lstrlenW(info->pwszName) * sizeof(WCHAR);
2241 else
2242 bytesNeeded += lstrlenW(unknown) * sizeof(WCHAR);
2243 bytesNeeded += sizeof(WCHAR); /* space */
2244 bytesNeeded += sizeof(WCHAR); /* left paren */
2245 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
2246 sizeof(WCHAR);
2247 bytesNeeded += sizeof(WCHAR); /* right paren */
2248 if (i < usage->cUsageIdentifier - 1)
2249 bytesNeeded += sepLen;
2251 if (!pbFormat)
2252 *pcbFormat = bytesNeeded;
2253 else if (*pcbFormat < bytesNeeded)
2255 *pcbFormat = bytesNeeded;
2256 SetLastError(ERROR_MORE_DATA);
2257 ret = FALSE;
2259 else
2261 LPWSTR str = pbFormat;
2263 *pcbFormat = bytesNeeded;
2264 for (i = 0; i < usage->cUsageIdentifier; i++)
2266 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2267 usage->rgpszUsageIdentifier[i],
2268 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2269 LPCSTR oidPtr;
2271 if (info)
2273 lstrcpyW(str, info->pwszName);
2274 str += lstrlenW(info->pwszName);
2276 else
2278 lstrcpyW(str, unknown);
2279 str += lstrlenW(unknown);
2281 *str++ = ' ';
2282 *str++ = '(';
2283 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2284 *str++ = *oidPtr;
2285 *str++ = ')';
2286 *str = 0;
2287 if (i < usage->cUsageIdentifier - 1)
2289 lstrcpyW(str, sep);
2290 str += sepLen / sizeof(WCHAR);
2294 LocalFree(usage);
2296 return ret;
2299 static struct BitToString netscapeCertTypeMap[] = {
2300 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2301 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2302 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2303 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2304 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2305 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2306 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2309 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2310 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2311 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2312 DWORD *pcbFormat)
2314 DWORD size;
2315 CRYPT_BIT_BLOB *bits;
2316 BOOL ret;
2318 if (!cbEncoded)
2320 SetLastError(E_INVALIDARG);
2321 return FALSE;
2323 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2324 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2326 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2327 DWORD bytesNeeded = sizeof(WCHAR);
2329 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
2330 if (!bits->cbData || bits->cbData > 1)
2332 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
2333 if (!pbFormat)
2334 *pcbFormat = bytesNeeded;
2335 else if (*pcbFormat < bytesNeeded)
2337 *pcbFormat = bytesNeeded;
2338 SetLastError(ERROR_MORE_DATA);
2339 ret = FALSE;
2341 else
2343 LPWSTR str = pbFormat;
2345 *pcbFormat = bytesNeeded;
2346 lstrcpyW(str, infoNotAvailable);
2349 else
2351 static BOOL stringsLoaded = FALSE;
2352 unsigned int i;
2353 DWORD bitStringLen;
2354 BOOL first = TRUE;
2356 if (!stringsLoaded)
2358 for (i = 0; i < ARRAY_SIZE(netscapeCertTypeMap); i++)
2359 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2360 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2361 stringsLoaded = TRUE;
2363 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, ARRAY_SIZE(netscapeCertTypeMap),
2364 NULL, &bitStringLen, &first);
2365 bytesNeeded += bitStringLen;
2366 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2367 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2368 bits->cbData, NULL, &size);
2369 bytesNeeded += size;
2370 if (!pbFormat)
2371 *pcbFormat = bytesNeeded;
2372 else if (*pcbFormat < bytesNeeded)
2374 *pcbFormat = bytesNeeded;
2375 SetLastError(ERROR_MORE_DATA);
2376 ret = FALSE;
2378 else
2380 LPWSTR str = pbFormat;
2382 bitStringLen = bytesNeeded;
2383 first = TRUE;
2384 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, ARRAY_SIZE(netscapeCertTypeMap),
2385 str, &bitStringLen, &first);
2386 str += bitStringLen / sizeof(WCHAR) - 1;
2387 *str++ = ' ';
2388 *str++ = '(';
2389 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2390 bits->cbData, str, &size);
2391 str += size / sizeof(WCHAR) - 1;
2392 *str++ = ')';
2393 *str = 0;
2396 LocalFree(bits);
2398 return ret;
2401 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2402 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2403 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2404 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2405 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2406 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2408 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2409 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2410 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2411 DWORD *pcbFormat)
2413 SPC_FINANCIAL_CRITERIA criteria;
2414 DWORD size = sizeof(criteria);
2415 BOOL ret = FALSE;
2417 if (!cbEncoded)
2419 SetLastError(E_INVALIDARG);
2420 return FALSE;
2422 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2423 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2424 &size)))
2426 static BOOL stringsLoaded = FALSE;
2427 DWORD bytesNeeded = sizeof(WCHAR);
2428 LPCWSTR sep;
2429 DWORD sepLen;
2431 if (!stringsLoaded)
2433 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria, ARRAY_SIZE(financialCriteria));
2434 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available, ARRAY_SIZE(available));
2435 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE, notAvailable, ARRAY_SIZE(notAvailable));
2436 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA, meetsCriteria, ARRAY_SIZE(meetsCriteria));
2437 LoadStringW(hInstance, IDS_YES, yes, ARRAY_SIZE(yes));
2438 LoadStringW(hInstance, IDS_NO, no, ARRAY_SIZE(no));
2439 stringsLoaded = TRUE;
2441 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2443 sep = crlf;
2444 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
2446 else
2448 sep = commaSpace;
2449 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
2451 bytesNeeded += lstrlenW(financialCriteria) * sizeof(WCHAR);
2452 if (criteria.fFinancialInfoAvailable)
2454 bytesNeeded += lstrlenW(available) * sizeof(WCHAR);
2455 bytesNeeded += sepLen;
2456 bytesNeeded += lstrlenW(meetsCriteria) * sizeof(WCHAR);
2457 if (criteria.fMeetsCriteria)
2458 bytesNeeded += lstrlenW(yes) * sizeof(WCHAR);
2459 else
2460 bytesNeeded += lstrlenW(no) * sizeof(WCHAR);
2462 else
2463 bytesNeeded += lstrlenW(notAvailable) * sizeof(WCHAR);
2464 if (!pbFormat)
2465 *pcbFormat = bytesNeeded;
2466 else if (*pcbFormat < bytesNeeded)
2468 *pcbFormat = bytesNeeded;
2469 SetLastError(ERROR_MORE_DATA);
2470 ret = FALSE;
2472 else
2474 LPWSTR str = pbFormat;
2476 *pcbFormat = bytesNeeded;
2477 lstrcpyW(str, financialCriteria);
2478 str += lstrlenW(financialCriteria);
2479 if (criteria.fFinancialInfoAvailable)
2481 lstrcpyW(str, available);
2482 str += lstrlenW(available);
2483 lstrcpyW(str, sep);
2484 str += sepLen / sizeof(WCHAR);
2485 lstrcpyW(str, meetsCriteria);
2486 str += lstrlenW(meetsCriteria);
2487 if (criteria.fMeetsCriteria)
2488 lstrcpyW(str, yes);
2489 else
2490 lstrcpyW(str, no);
2492 else
2494 lstrcpyW(str, notAvailable);
2498 return ret;
2501 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2502 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2503 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2504 DWORD *pcbFormat)
2506 CERT_NAME_VALUE *value;
2507 DWORD size;
2508 BOOL ret;
2510 if (!cbEncoded)
2512 SetLastError(E_INVALIDARG);
2513 return FALSE;
2515 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2516 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2518 if (!pbFormat)
2519 *pcbFormat = value->Value.cbData;
2520 else if (*pcbFormat < value->Value.cbData)
2522 *pcbFormat = value->Value.cbData;
2523 SetLastError(ERROR_MORE_DATA);
2524 ret = FALSE;
2526 else
2528 LPWSTR str = pbFormat;
2530 *pcbFormat = value->Value.cbData;
2531 lstrcpyW(str, (LPWSTR)value->Value.pbData);
2534 return ret;
2537 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2538 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2540 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2541 DWORD formatStrType, LPCSTR lpszStructType)
2543 CryptFormatObjectFunc format = NULL;
2545 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2547 SetLastError(ERROR_FILE_NOT_FOUND);
2548 return NULL;
2550 if (IS_INTOID(lpszStructType))
2552 switch (LOWORD(lpszStructType))
2554 case LOWORD(X509_KEY_USAGE):
2555 format = CRYPT_FormatKeyUsage;
2556 break;
2557 case LOWORD(X509_ALTERNATE_NAME):
2558 format = CRYPT_FormatAltName;
2559 break;
2560 case LOWORD(X509_BASIC_CONSTRAINTS2):
2561 format = CRYPT_FormatBasicConstraints2;
2562 break;
2563 case LOWORD(X509_AUTHORITY_KEY_ID2):
2564 format = CRYPT_FormatAuthorityKeyId2;
2565 break;
2566 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2567 format = CRYPT_FormatAuthorityInfoAccess;
2568 break;
2569 case LOWORD(X509_CRL_DIST_POINTS):
2570 format = CRYPT_FormatCRLDistPoints;
2571 break;
2572 case LOWORD(X509_ENHANCED_KEY_USAGE):
2573 format = CRYPT_FormatEnhancedKeyUsage;
2574 break;
2575 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2576 format = CRYPT_FormatSpcFinancialCriteria;
2577 break;
2580 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2581 format = CRYPT_FormatAltName;
2582 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2583 format = CRYPT_FormatAltName;
2584 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2585 format = CRYPT_FormatKeyUsage;
2586 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2587 format = CRYPT_FormatAltName;
2588 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2589 format = CRYPT_FormatAltName;
2590 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2591 format = CRYPT_FormatBasicConstraints2;
2592 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2593 format = CRYPT_FormatAuthorityInfoAccess;
2594 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2595 format = CRYPT_FormatAuthorityKeyId2;
2596 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2597 format = CRYPT_FormatCRLDistPoints;
2598 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2599 format = CRYPT_FormatEnhancedKeyUsage;
2600 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2601 format = CRYPT_FormatNetscapeCertType;
2602 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2603 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2604 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2605 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2606 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2607 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2608 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2609 format = CRYPT_FormatUnicodeString;
2610 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2611 format = CRYPT_FormatSpcFinancialCriteria;
2612 return format;
2615 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2616 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2617 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2619 CryptFormatObjectFunc format = NULL;
2620 HCRYPTOIDFUNCADDR hFunc = NULL;
2621 BOOL ret = FALSE;
2623 TRACE("(%08lx, %ld, %08lx, %p, %s, %p, %ld, %p, %p)\n", dwCertEncodingType,
2624 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2625 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2627 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2628 dwFormatStrType, lpszStructType)))
2630 static HCRYPTOIDFUNCSET set = NULL;
2632 if (!set)
2633 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2634 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2635 (void **)&format, &hFunc);
2637 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2638 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2639 format = CRYPT_FormatHexString;
2640 if (format)
2641 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2642 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2643 pcbFormat);
2644 if (hFunc)
2645 CryptFreeOIDFunctionAddress(hFunc, 0);
2646 return ret;