server: Allow reading directly from console handle.
[wine.git] / dlls / crypt32 / object.c
blob83cdd535a3c4d470f32471c3757c761cdc6b0b17
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 "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("(%d, %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 %d\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("(%d, %p, %08x, %08x, %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_FILE)
634 WARN("don't know what to do for type %d embedded signed messages\n",
635 dwObjectType);
636 SetLastError(E_INVALIDARG);
637 return FALSE;
639 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
640 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
641 if (file != INVALID_HANDLE_VALUE)
643 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
644 if (ret)
646 SIP_DISPATCH_INFO sip;
648 memset(&sip, 0, sizeof(sip));
649 sip.cbSize = sizeof(sip);
650 ret = CryptSIPLoad(&subject, 0, &sip);
651 if (ret)
653 SIP_SUBJECTINFO subjectInfo;
654 CERT_BLOB blob;
655 DWORD encodingType;
657 memset(&subjectInfo, 0, sizeof(subjectInfo));
658 subjectInfo.cbSize = sizeof(subjectInfo);
659 subjectInfo.pgSubjectType = &subject;
660 subjectInfo.hFile = file;
661 subjectInfo.pwsFileName = pvObject;
662 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
663 NULL);
664 if (ret)
666 blob.pbData = CryptMemAlloc(blob.cbData);
667 if (blob.pbData)
669 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
670 &blob.cbData, blob.pbData);
671 if (ret)
673 ret = CRYPT_QueryMessageObject(
674 CERT_QUERY_OBJECT_BLOB, &blob,
675 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
676 CERT_QUERY_FORMAT_FLAG_BINARY,
677 pdwMsgAndCertEncodingType, NULL, NULL,
678 phCertStore, phMsg);
679 if (ret && pdwContentType)
680 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
682 CryptMemFree(blob.pbData);
684 else
686 SetLastError(ERROR_OUTOFMEMORY);
687 ret = FALSE;
692 CloseHandle(file);
694 TRACE("returning %d\n", ret);
695 return ret;
698 static BOOL CRYPT_QueryPFXObject(DWORD dwObjectType, const void *pvObject,
699 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
700 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
701 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
703 CRYPT_DATA_BLOB blob = {0}, *ptr;
704 BOOL ret;
706 TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
707 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
708 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
709 phMsg);
711 switch (dwObjectType)
713 case CERT_QUERY_OBJECT_FILE:
714 if (!CRYPT_ReadBlobFromFile(pvObject, &blob)) return FALSE;
715 ptr = &blob;
716 break;
718 case CERT_QUERY_OBJECT_BLOB:
719 ptr = (CRYPT_DATA_BLOB *)pvObject;
720 break;
722 default:
723 return FALSE;
726 ret = PFXIsPFXBlob(ptr);
727 if (ret)
729 if (pdwMsgAndCertEncodingType) *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
730 if (pdwContentType) *pdwContentType = CERT_QUERY_CONTENT_PFX;
731 if (pdwFormatType) *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
732 if (phCertStore) *phCertStore = NULL;
733 if (phMsg) *phMsg = NULL;
736 CryptMemFree(blob.pbData);
737 return ret;
740 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
741 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
742 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
743 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
744 const void **ppvContext)
746 static const DWORD unimplementedTypes =
747 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
748 BOOL ret = TRUE;
750 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
751 dwObjectType, pvObject, dwExpectedContentTypeFlags,
752 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
753 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
755 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
756 dwObjectType != CERT_QUERY_OBJECT_FILE)
758 WARN("unsupported type %d\n", dwObjectType);
759 SetLastError(E_INVALIDARG);
760 return FALSE;
762 if (!pvObject)
764 WARN("missing required argument\n");
765 SetLastError(E_INVALIDARG);
766 return FALSE;
768 if (dwExpectedContentTypeFlags & unimplementedTypes)
769 WARN("unimplemented for types %08x\n",
770 dwExpectedContentTypeFlags & unimplementedTypes);
772 if (pdwFormatType)
773 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
774 if (phCertStore)
775 *phCertStore = NULL;
776 if (phMsg)
777 *phMsg = NULL;
778 if (ppvContext)
779 *ppvContext = NULL;
781 ret = FALSE;
782 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
783 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
784 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
786 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
787 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
788 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
789 ppvContext);
791 if (!ret &&
792 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
794 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
795 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
797 if (!ret &&
798 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
799 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
800 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
802 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
803 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
804 phCertStore, ppvContext);
806 if (!ret &&
807 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
808 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
810 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
811 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
812 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
813 phCertStore, phMsg);
815 if (!ret &&
816 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
818 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
819 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
820 phCertStore, phMsg);
822 if (!ret &&
823 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PFX))
825 ret = CRYPT_QueryPFXObject(dwObjectType, pvObject,
826 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
827 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
828 phCertStore, phMsg);
830 if (!ret)
831 SetLastError(CRYPT_E_NO_MATCH);
832 TRACE("returning %d\n", ret);
833 return ret;
836 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
837 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
838 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
839 DWORD *pcbFormat)
841 BOOL ret;
842 DWORD bytesNeeded;
844 if (cbEncoded)
845 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
846 else
847 bytesNeeded = sizeof(WCHAR);
848 if (!pbFormat)
850 *pcbFormat = bytesNeeded;
851 ret = TRUE;
853 else if (*pcbFormat < bytesNeeded)
855 *pcbFormat = bytesNeeded;
856 SetLastError(ERROR_MORE_DATA);
857 ret = FALSE;
859 else
861 DWORD i;
862 LPWSTR ptr = pbFormat;
864 *pcbFormat = bytesNeeded;
865 if (cbEncoded)
867 for (i = 0; i < cbEncoded; i++)
869 if (i < cbEncoded - 1)
870 ptr += swprintf(ptr, 4, L"%02x ", pbEncoded[i]);
871 else
872 ptr += swprintf(ptr, 3, L"%02x", pbEncoded[i]);
875 else
876 *ptr = 0;
877 ret = TRUE;
879 return ret;
882 #define MAX_STRING_RESOURCE_LEN 128
884 static const WCHAR commaSpace[] = L", ";
886 struct BitToString
888 BYTE bit;
889 int id;
890 WCHAR str[MAX_STRING_RESOURCE_LEN];
893 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
894 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
896 DWORD bytesNeeded = sizeof(WCHAR);
897 unsigned int i;
898 BOOL ret = TRUE, localFirst = *first;
900 for (i = 0; i < mapEntries; i++)
901 if (bits & map[i].bit)
903 if (!localFirst)
904 bytesNeeded += lstrlenW(commaSpace) * sizeof(WCHAR);
905 localFirst = FALSE;
906 bytesNeeded += lstrlenW(map[i].str) * sizeof(WCHAR);
908 if (!pbFormat)
910 *first = localFirst;
911 *pcbFormat = bytesNeeded;
913 else if (*pcbFormat < bytesNeeded)
915 *first = localFirst;
916 *pcbFormat = bytesNeeded;
917 SetLastError(ERROR_MORE_DATA);
918 ret = FALSE;
920 else
922 LPWSTR str = pbFormat;
924 localFirst = *first;
925 *pcbFormat = bytesNeeded;
926 for (i = 0; i < mapEntries; i++)
927 if (bits & map[i].bit)
929 if (!localFirst)
931 lstrcpyW(str, commaSpace);
932 str += lstrlenW(commaSpace);
934 localFirst = FALSE;
935 lstrcpyW(str, map[i].str);
936 str += lstrlenW(map[i].str);
938 *first = localFirst;
940 return ret;
943 static struct BitToString keyUsageByte0Map[] = {
944 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
945 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
946 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
947 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
948 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
949 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
950 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
951 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
952 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
954 static struct BitToString keyUsageByte1Map[] = {
955 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
958 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
959 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
960 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
961 DWORD *pcbFormat)
963 DWORD size;
964 CRYPT_BIT_BLOB *bits;
965 BOOL ret;
967 if (!cbEncoded)
969 SetLastError(E_INVALIDARG);
970 return FALSE;
972 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
973 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
975 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
976 DWORD bytesNeeded = sizeof(WCHAR);
978 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
979 if (!bits->cbData || bits->cbData > 2)
981 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
982 if (!pbFormat)
983 *pcbFormat = bytesNeeded;
984 else if (*pcbFormat < bytesNeeded)
986 *pcbFormat = bytesNeeded;
987 SetLastError(ERROR_MORE_DATA);
988 ret = FALSE;
990 else
992 LPWSTR str = pbFormat;
994 *pcbFormat = bytesNeeded;
995 lstrcpyW(str, infoNotAvailable);
998 else
1000 static BOOL stringsLoaded = FALSE;
1001 unsigned int i;
1002 DWORD bitStringLen;
1003 BOOL first = TRUE;
1005 if (!stringsLoaded)
1007 for (i = 0; i < ARRAY_SIZE(keyUsageByte0Map); i++)
1008 LoadStringW(hInstance, keyUsageByte0Map[i].id, keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
1009 for (i = 0; i < ARRAY_SIZE(keyUsageByte1Map); i++)
1010 LoadStringW(hInstance, keyUsageByte1Map[i].id, keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
1011 stringsLoaded = TRUE;
1013 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, ARRAY_SIZE(keyUsageByte0Map),
1014 NULL, &bitStringLen, &first);
1015 bytesNeeded += bitStringLen;
1016 if (bits->cbData == 2)
1018 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, ARRAY_SIZE(keyUsageByte1Map),
1019 NULL, &bitStringLen, &first);
1020 bytesNeeded += bitStringLen;
1022 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
1023 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1024 bits->cbData, NULL, &size);
1025 bytesNeeded += size;
1026 if (!pbFormat)
1027 *pcbFormat = bytesNeeded;
1028 else if (*pcbFormat < bytesNeeded)
1030 *pcbFormat = bytesNeeded;
1031 SetLastError(ERROR_MORE_DATA);
1032 ret = FALSE;
1034 else
1036 LPWSTR str = pbFormat;
1038 bitStringLen = bytesNeeded;
1039 first = TRUE;
1040 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, ARRAY_SIZE(keyUsageByte0Map),
1041 str, &bitStringLen, &first);
1042 str += bitStringLen / sizeof(WCHAR) - 1;
1043 if (bits->cbData == 2)
1045 bitStringLen = bytesNeeded;
1046 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, ARRAY_SIZE(keyUsageByte1Map),
1047 str, &bitStringLen, &first);
1048 str += bitStringLen / sizeof(WCHAR) - 1;
1050 *str++ = ' ';
1051 *str++ = '(';
1052 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1053 bits->cbData, str, &size);
1054 str += size / sizeof(WCHAR) - 1;
1055 *str++ = ')';
1056 *str = 0;
1059 LocalFree(bits);
1061 return ret;
1064 static const WCHAR crlf[] = L"\r\n";
1066 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1067 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1068 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1069 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1071 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1072 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1073 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1074 DWORD *pcbFormat)
1076 DWORD size;
1077 CERT_BASIC_CONSTRAINTS2_INFO *info;
1078 BOOL ret;
1080 if (!cbEncoded)
1082 SetLastError(E_INVALIDARG);
1083 return FALSE;
1085 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1086 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1088 static BOOL stringsLoaded = FALSE;
1089 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1090 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1091 LPCWSTR sep, subjectType;
1092 DWORD sepLen;
1094 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1096 sep = crlf;
1097 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
1099 else
1101 sep = commaSpace;
1102 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
1105 if (!stringsLoaded)
1107 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader, ARRAY_SIZE(subjectTypeHeader));
1108 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA, ARRAY_SIZE(subjectTypeCA));
1109 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT, subjectTypeEndCert, ARRAY_SIZE(subjectTypeEndCert));
1110 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader, ARRAY_SIZE(pathLengthHeader));
1111 stringsLoaded = TRUE;
1113 bytesNeeded += lstrlenW(subjectTypeHeader) * sizeof(WCHAR);
1114 if (info->fCA)
1115 subjectType = subjectTypeCA;
1116 else
1117 subjectType = subjectTypeEndCert;
1118 bytesNeeded += lstrlenW(subjectType) * sizeof(WCHAR);
1119 bytesNeeded += sepLen;
1120 bytesNeeded += lstrlenW(pathLengthHeader) * sizeof(WCHAR);
1121 if (info->fPathLenConstraint)
1122 swprintf(pathLength, ARRAY_SIZE(pathLength), L"%d", info->dwPathLenConstraint);
1123 else
1124 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength, ARRAY_SIZE(pathLength));
1125 bytesNeeded += lstrlenW(pathLength) * sizeof(WCHAR);
1126 if (!pbFormat)
1127 *pcbFormat = bytesNeeded;
1128 else if (*pcbFormat < bytesNeeded)
1130 *pcbFormat = bytesNeeded;
1131 SetLastError(ERROR_MORE_DATA);
1132 ret = FALSE;
1134 else
1136 LPWSTR str = pbFormat;
1138 *pcbFormat = bytesNeeded;
1139 lstrcpyW(str, subjectTypeHeader);
1140 str += lstrlenW(subjectTypeHeader);
1141 lstrcpyW(str, subjectType);
1142 str += lstrlenW(subjectType);
1143 lstrcpyW(str, sep);
1144 str += sepLen / sizeof(WCHAR);
1145 lstrcpyW(str, pathLengthHeader);
1146 str += lstrlenW(pathLengthHeader);
1147 lstrcpyW(str, pathLength);
1149 LocalFree(info);
1151 return ret;
1154 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1155 LPWSTR str, DWORD *pcbStr)
1157 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1158 DWORD bytesNeeded;
1159 BOOL ret;
1161 LoadStringW(hInstance, id, buf, ARRAY_SIZE(buf));
1162 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1163 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1164 bytesNeeded += lstrlenW(buf) * sizeof(WCHAR);
1165 if (!str)
1167 *pcbStr = bytesNeeded;
1168 ret = TRUE;
1170 else if (*pcbStr < bytesNeeded)
1172 *pcbStr = bytesNeeded;
1173 SetLastError(ERROR_MORE_DATA);
1174 ret = FALSE;
1176 else
1178 *pcbStr = bytesNeeded;
1179 lstrcpyW(str, buf);
1180 str += lstrlenW(str);
1181 bytesNeeded -= lstrlenW(str) * sizeof(WCHAR);
1182 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1183 blob->pbData, blob->cbData, str, &bytesNeeded);
1185 return ret;
1188 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1189 DWORD *pcbStr)
1191 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1194 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1195 DWORD *pcbStr)
1197 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1198 str, pcbStr);
1201 static const WCHAR indent[] = L" ";
1202 static const WCHAR colonCrlf[] = L":\r\n";
1204 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1205 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1207 BOOL ret;
1208 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1209 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1210 WCHAR ipAddrBuf[32];
1211 WCHAR maskBuf[16];
1212 DWORD bytesNeeded = sizeof(WCHAR);
1213 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1215 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1216 bytesNeeded += indentLevel * lstrlenW(indent) * sizeof(WCHAR);
1217 switch (entry->dwAltNameChoice)
1219 case CERT_ALT_NAME_RFC822_NAME:
1220 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf, ARRAY_SIZE(buf));
1221 bytesNeeded += lstrlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
1222 ret = TRUE;
1223 break;
1224 case CERT_ALT_NAME_DNS_NAME:
1225 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf, ARRAY_SIZE(buf));
1226 bytesNeeded += lstrlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
1227 ret = TRUE;
1228 break;
1229 case CERT_ALT_NAME_DIRECTORY_NAME:
1231 DWORD directoryNameLen;
1233 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1234 strType |= CERT_NAME_STR_CRLF_FLAG;
1235 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1236 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
1237 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf, ARRAY_SIZE(buf));
1238 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1239 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1240 bytesNeeded += lstrlenW(colonCrlf) * sizeof(WCHAR);
1241 else
1242 bytesNeeded += sizeof(WCHAR); /* '=' */
1243 ret = TRUE;
1244 break;
1246 case CERT_ALT_NAME_URL:
1247 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf, ARRAY_SIZE(buf));
1248 bytesNeeded += lstrlenW(entry->u.pwszURL) * sizeof(WCHAR);
1249 ret = TRUE;
1250 break;
1251 case CERT_ALT_NAME_IP_ADDRESS:
1253 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf, ARRAY_SIZE(buf));
1254 if (entry->u.IPAddress.cbData == 8)
1256 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1258 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask, ARRAY_SIZE(mask));
1259 bytesNeeded += lstrlenW(mask) * sizeof(WCHAR);
1260 swprintf(ipAddrBuf, ARRAY_SIZE(ipAddrBuf), L"%d.%d.%d.%d",
1261 entry->u.IPAddress.pbData[0],
1262 entry->u.IPAddress.pbData[1],
1263 entry->u.IPAddress.pbData[2],
1264 entry->u.IPAddress.pbData[3]);
1265 bytesNeeded += lstrlenW(ipAddrBuf) * sizeof(WCHAR);
1266 /* indent again, for the mask line */
1267 bytesNeeded += indentLevel * lstrlenW(indent) * sizeof(WCHAR);
1268 swprintf(maskBuf, ARRAY_SIZE(maskBuf), L"%d.%d.%d.%d",
1269 entry->u.IPAddress.pbData[4],
1270 entry->u.IPAddress.pbData[5],
1271 entry->u.IPAddress.pbData[6],
1272 entry->u.IPAddress.pbData[7]);
1273 bytesNeeded += lstrlenW(maskBuf) * sizeof(WCHAR);
1274 bytesNeeded += lstrlenW(crlf) * sizeof(WCHAR);
1276 else
1278 swprintf(ipAddrBuf, ARRAY_SIZE(ipAddrBuf), L"%d.%d.%d.%d/%d.%d.%d.%d",
1279 entry->u.IPAddress.pbData[0],
1280 entry->u.IPAddress.pbData[1],
1281 entry->u.IPAddress.pbData[2],
1282 entry->u.IPAddress.pbData[3],
1283 entry->u.IPAddress.pbData[4],
1284 entry->u.IPAddress.pbData[5],
1285 entry->u.IPAddress.pbData[6],
1286 entry->u.IPAddress.pbData[7]);
1287 bytesNeeded += (lstrlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1289 ret = TRUE;
1291 else
1293 FIXME("unknown IP address format (%d bytes)\n",
1294 entry->u.IPAddress.cbData);
1295 ret = FALSE;
1297 break;
1299 default:
1300 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1301 ret = FALSE;
1303 if (ret)
1305 bytesNeeded += lstrlenW(buf) * sizeof(WCHAR);
1306 if (!str)
1307 *pcbStr = bytesNeeded;
1308 else if (*pcbStr < bytesNeeded)
1310 *pcbStr = bytesNeeded;
1311 SetLastError(ERROR_MORE_DATA);
1312 ret = FALSE;
1314 else
1316 DWORD i;
1318 *pcbStr = bytesNeeded;
1319 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1321 for (i = 0; i < indentLevel; i++)
1323 lstrcpyW(str, indent);
1324 str += lstrlenW(indent);
1327 lstrcpyW(str, buf);
1328 str += lstrlenW(str);
1329 switch (entry->dwAltNameChoice)
1331 case CERT_ALT_NAME_RFC822_NAME:
1332 case CERT_ALT_NAME_DNS_NAME:
1333 case CERT_ALT_NAME_URL:
1334 lstrcpyW(str, entry->u.pwszURL);
1335 break;
1336 case CERT_ALT_NAME_DIRECTORY_NAME:
1337 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1339 lstrcpyW(str, colonCrlf);
1340 str += lstrlenW(colonCrlf);
1342 else
1343 *str++ = '=';
1344 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1345 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1346 bytesNeeded / sizeof(WCHAR));
1347 break;
1348 case CERT_ALT_NAME_IP_ADDRESS:
1349 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1351 lstrcpyW(str, ipAddrBuf);
1352 str += lstrlenW(ipAddrBuf);
1353 lstrcpyW(str, crlf);
1354 str += lstrlenW(crlf);
1355 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1357 for (i = 0; i < indentLevel; i++)
1359 lstrcpyW(str, indent);
1360 str += lstrlenW(indent);
1363 lstrcpyW(str, mask);
1364 str += lstrlenW(mask);
1365 lstrcpyW(str, maskBuf);
1367 else
1368 lstrcpyW(str, ipAddrBuf);
1369 break;
1373 return ret;
1376 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1377 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1379 DWORD i, size, bytesNeeded = 0;
1380 BOOL ret = TRUE;
1381 LPCWSTR sep;
1382 DWORD sepLen;
1384 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1386 sep = crlf;
1387 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
1389 else
1391 sep = commaSpace;
1392 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
1395 for (i = 0; ret && i < name->cAltEntry; i++)
1397 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1398 &name->rgAltEntry[i], NULL, &size);
1399 if (ret)
1401 bytesNeeded += size - sizeof(WCHAR);
1402 if (i < name->cAltEntry - 1)
1403 bytesNeeded += sepLen;
1406 if (ret)
1408 bytesNeeded += sizeof(WCHAR);
1409 if (!str)
1410 *pcbStr = bytesNeeded;
1411 else if (*pcbStr < bytesNeeded)
1413 *pcbStr = bytesNeeded;
1414 SetLastError(ERROR_MORE_DATA);
1415 ret = FALSE;
1417 else
1419 *pcbStr = bytesNeeded;
1420 for (i = 0; ret && i < name->cAltEntry; i++)
1422 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1423 &name->rgAltEntry[i], str, &size);
1424 if (ret)
1426 str += size / sizeof(WCHAR) - 1;
1427 if (i < name->cAltEntry - 1)
1429 lstrcpyW(str, sep);
1430 str += sepLen / sizeof(WCHAR);
1436 return ret;
1439 static const WCHAR colonSep[] = L": ";
1441 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1442 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1443 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1444 DWORD *pcbFormat)
1446 BOOL ret;
1447 CERT_ALT_NAME_INFO *info;
1448 DWORD size;
1450 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1451 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1453 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1454 LocalFree(info);
1456 return ret;
1459 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1460 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1462 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1463 DWORD bytesNeeded, sepLen;
1464 LPCWSTR sep;
1465 BOOL ret;
1467 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, ARRAY_SIZE(buf));
1468 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1469 &bytesNeeded);
1470 bytesNeeded += lstrlenW(buf) * sizeof(WCHAR);
1471 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1473 sep = colonCrlf;
1474 sepLen = lstrlenW(colonCrlf) * sizeof(WCHAR);
1476 else
1478 sep = colonSep;
1479 sepLen = lstrlenW(colonSep) * sizeof(WCHAR);
1481 bytesNeeded += sepLen;
1482 if (ret)
1484 if (!str)
1485 *pcbStr = bytesNeeded;
1486 else if (*pcbStr < bytesNeeded)
1488 *pcbStr = bytesNeeded;
1489 SetLastError(ERROR_MORE_DATA);
1490 ret = FALSE;
1492 else
1494 *pcbStr = bytesNeeded;
1495 lstrcpyW(str, buf);
1496 bytesNeeded -= lstrlenW(str) * sizeof(WCHAR);
1497 str += lstrlenW(str);
1498 lstrcpyW(str, sep);
1499 str += sepLen / sizeof(WCHAR);
1500 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1501 &bytesNeeded);
1504 return ret;
1507 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1508 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1509 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1510 DWORD *pcbFormat)
1512 CERT_AUTHORITY_KEY_ID2_INFO *info;
1513 DWORD size;
1514 BOOL ret = FALSE;
1516 if (!cbEncoded)
1518 SetLastError(E_INVALIDARG);
1519 return FALSE;
1521 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1522 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1524 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1525 LPCWSTR sep;
1526 DWORD sepLen;
1527 BOOL needSeparator = FALSE;
1529 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1531 sep = crlf;
1532 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
1534 else
1536 sep = commaSpace;
1537 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
1540 if (info->KeyId.cbData)
1542 needSeparator = TRUE;
1543 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1544 if (ret)
1546 /* don't include NULL-terminator more than once */
1547 bytesNeeded += size - sizeof(WCHAR);
1550 if (info->AuthorityCertIssuer.cAltEntry)
1552 if (needSeparator)
1553 bytesNeeded += sepLen;
1554 needSeparator = TRUE;
1555 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1556 &info->AuthorityCertIssuer, NULL, &size);
1557 if (ret)
1559 /* don't include NULL-terminator more than once */
1560 bytesNeeded += size - sizeof(WCHAR);
1563 if (info->AuthorityCertSerialNumber.cbData)
1565 if (needSeparator)
1566 bytesNeeded += sepLen;
1567 ret = CRYPT_FormatCertSerialNumber(
1568 &info->AuthorityCertSerialNumber, NULL, &size);
1569 if (ret)
1571 /* don't include NULL-terminator more than once */
1572 bytesNeeded += size - sizeof(WCHAR);
1575 if (ret)
1577 if (!pbFormat)
1578 *pcbFormat = bytesNeeded;
1579 else if (*pcbFormat < bytesNeeded)
1581 *pcbFormat = bytesNeeded;
1582 SetLastError(ERROR_MORE_DATA);
1583 ret = FALSE;
1585 else
1587 LPWSTR str = pbFormat;
1589 *pcbFormat = bytesNeeded;
1590 needSeparator = FALSE;
1591 if (info->KeyId.cbData)
1593 needSeparator = TRUE;
1594 /* Overestimate size available, it's already been checked
1595 * above.
1597 size = bytesNeeded;
1598 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1599 if (ret)
1600 str += size / sizeof(WCHAR) - 1;
1602 if (info->AuthorityCertIssuer.cAltEntry)
1604 if (needSeparator)
1606 lstrcpyW(str, sep);
1607 str += sepLen / sizeof(WCHAR);
1609 needSeparator = TRUE;
1610 /* Overestimate size available, it's already been checked
1611 * above.
1613 size = bytesNeeded;
1614 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1615 &info->AuthorityCertIssuer, str, &size);
1616 if (ret)
1617 str += size / sizeof(WCHAR) - 1;
1619 if (info->AuthorityCertSerialNumber.cbData)
1621 if (needSeparator)
1623 lstrcpyW(str, sep);
1624 str += sepLen / sizeof(WCHAR);
1626 /* Overestimate size available, it's already been checked
1627 * above.
1629 size = bytesNeeded;
1630 ret = CRYPT_FormatCertSerialNumber(
1631 &info->AuthorityCertSerialNumber, str, &size);
1635 LocalFree(info);
1637 return ret;
1640 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1641 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1642 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1643 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1644 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1645 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1647 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1648 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1649 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1650 DWORD *pcbFormat)
1652 CERT_AUTHORITY_INFO_ACCESS *info;
1653 DWORD size;
1654 BOOL ret = FALSE;
1656 if (!cbEncoded)
1658 SetLastError(E_INVALIDARG);
1659 return FALSE;
1661 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1662 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1663 NULL, &info, &size)))
1665 DWORD bytesNeeded = sizeof(WCHAR);
1667 if (!info->cAccDescr)
1669 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1671 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
1672 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
1673 if (!pbFormat)
1674 *pcbFormat = bytesNeeded;
1675 else if (*pcbFormat < bytesNeeded)
1677 *pcbFormat = bytesNeeded;
1678 SetLastError(ERROR_MORE_DATA);
1679 ret = FALSE;
1681 else
1683 *pcbFormat = bytesNeeded;
1684 lstrcpyW(pbFormat, infoNotAvailable);
1687 else
1689 static const WCHAR equal[] = L"=";
1690 static BOOL stringsLoaded = FALSE;
1691 DWORD i;
1692 LPCWSTR headingSep, accessMethodSep, locationSep;
1693 WCHAR accessDescrNum[11];
1695 if (!stringsLoaded)
1697 LoadStringW(hInstance, IDS_AIA, aia, ARRAY_SIZE(aia));
1698 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod, ARRAY_SIZE(accessMethod));
1699 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp, ARRAY_SIZE(ocsp));
1700 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers, ARRAY_SIZE(caIssuers));
1701 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown, ARRAY_SIZE(unknown));
1702 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation, ARRAY_SIZE(accessLocation));
1703 stringsLoaded = TRUE;
1705 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1707 headingSep = crlf;
1708 accessMethodSep = crlf;
1709 locationSep = colonCrlf;
1711 else
1713 headingSep = colonSep;
1714 accessMethodSep = commaSpace;
1715 locationSep = equal;
1718 for (i = 0; ret && i < info->cAccDescr; i++)
1720 /* Heading */
1721 bytesNeeded += sizeof(WCHAR); /* left bracket */
1722 swprintf(accessDescrNum, ARRAY_SIZE(accessDescrNum), L"%d", i + 1);
1723 bytesNeeded += lstrlenW(accessDescrNum) * sizeof(WCHAR);
1724 bytesNeeded += sizeof(WCHAR); /* right bracket */
1725 bytesNeeded += lstrlenW(aia) * sizeof(WCHAR);
1726 bytesNeeded += lstrlenW(headingSep) * sizeof(WCHAR);
1727 /* Access method */
1728 bytesNeeded += lstrlenW(accessMethod) * sizeof(WCHAR);
1729 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1730 bytesNeeded += lstrlenW(indent) * sizeof(WCHAR);
1731 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1732 szOID_PKIX_OCSP))
1733 bytesNeeded += lstrlenW(ocsp) * sizeof(WCHAR);
1734 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1735 szOID_PKIX_CA_ISSUERS))
1736 bytesNeeded += lstrlenW(caIssuers) * sizeof(caIssuers);
1737 else
1738 bytesNeeded += lstrlenW(unknown) * sizeof(WCHAR);
1739 bytesNeeded += sizeof(WCHAR); /* space */
1740 bytesNeeded += sizeof(WCHAR); /* left paren */
1741 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1742 * sizeof(WCHAR);
1743 bytesNeeded += sizeof(WCHAR); /* right paren */
1744 /* Delimiter between access method and location */
1745 bytesNeeded += lstrlenW(accessMethodSep) * sizeof(WCHAR);
1746 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1747 bytesNeeded += lstrlenW(indent) * sizeof(WCHAR);
1748 bytesNeeded += lstrlenW(accessLocation) * sizeof(WCHAR);
1749 bytesNeeded += lstrlenW(locationSep) * sizeof(WCHAR);
1750 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1751 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1752 if (ret)
1753 bytesNeeded += size - sizeof(WCHAR);
1754 /* Need extra delimiter between access method entries */
1755 if (i < info->cAccDescr - 1)
1756 bytesNeeded += lstrlenW(accessMethodSep) * sizeof(WCHAR);
1758 if (ret)
1760 if (!pbFormat)
1761 *pcbFormat = bytesNeeded;
1762 else if (*pcbFormat < bytesNeeded)
1764 *pcbFormat = bytesNeeded;
1765 SetLastError(ERROR_MORE_DATA);
1766 ret = FALSE;
1768 else
1770 LPWSTR str = pbFormat;
1771 DWORD altNameEntrySize;
1773 *pcbFormat = bytesNeeded;
1774 for (i = 0; ret && i < info->cAccDescr; i++)
1776 LPCSTR oidPtr;
1778 *str++ = '[';
1779 swprintf(accessDescrNum, ARRAY_SIZE(accessDescrNum), L"%d", i + 1);
1780 lstrcpyW(str, accessDescrNum);
1781 str += lstrlenW(accessDescrNum);
1782 *str++ = ']';
1783 lstrcpyW(str, aia);
1784 str += lstrlenW(aia);
1785 lstrcpyW(str, headingSep);
1786 str += lstrlenW(headingSep);
1787 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1789 lstrcpyW(str, indent);
1790 str += lstrlenW(indent);
1792 lstrcpyW(str, accessMethod);
1793 str += lstrlenW(accessMethod);
1794 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1795 szOID_PKIX_OCSP))
1797 lstrcpyW(str, ocsp);
1798 str += lstrlenW(ocsp);
1800 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1801 szOID_PKIX_CA_ISSUERS))
1803 lstrcpyW(str, caIssuers);
1804 str += lstrlenW(caIssuers);
1806 else
1808 lstrcpyW(str, unknown);
1809 str += lstrlenW(unknown);
1811 *str++ = ' ';
1812 *str++ = '(';
1813 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1814 *oidPtr; oidPtr++, str++)
1815 *str = *oidPtr;
1816 *str++ = ')';
1817 lstrcpyW(str, accessMethodSep);
1818 str += lstrlenW(accessMethodSep);
1819 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1821 lstrcpyW(str, indent);
1822 str += lstrlenW(indent);
1824 lstrcpyW(str, accessLocation);
1825 str += lstrlenW(accessLocation);
1826 lstrcpyW(str, locationSep);
1827 str += lstrlenW(locationSep);
1828 /* This overestimates the size available, but that
1829 * won't matter since we checked earlier whether enough
1830 * space for the entire string was available.
1832 altNameEntrySize = bytesNeeded;
1833 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1834 &info->rgAccDescr[i].AccessLocation, str,
1835 &altNameEntrySize);
1836 if (ret)
1837 str += altNameEntrySize / sizeof(WCHAR) - 1;
1838 if (i < info->cAccDescr - 1)
1840 lstrcpyW(str, accessMethodSep);
1841 str += lstrlenW(accessMethodSep);
1847 LocalFree(info);
1849 return ret;
1852 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1853 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1854 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1855 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1856 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1857 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1859 struct reason_map_entry
1861 BYTE reasonBit;
1862 LPWSTR reason;
1863 int id;
1865 static struct reason_map_entry reason_map[] = {
1866 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1867 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1868 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1869 IDS_REASON_AFFILIATION_CHANGED },
1870 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1871 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1872 IDS_REASON_CESSATION_OF_OPERATION },
1873 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1874 IDS_REASON_CERTIFICATE_HOLD },
1877 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1878 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1880 static const WCHAR sep[] = L", ";
1881 static BOOL stringsLoaded = FALSE;
1882 unsigned int i, numReasons = 0;
1883 BOOL ret = TRUE;
1884 DWORD bytesNeeded = sizeof(WCHAR);
1885 WCHAR bits[6];
1887 if (!stringsLoaded)
1889 for (i = 0; i < ARRAY_SIZE(reason_map); i++)
1890 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1891 MAX_STRING_RESOURCE_LEN);
1892 stringsLoaded = TRUE;
1894 /* No need to check reasonFlags->cbData, we already know it's positive.
1895 * Ignore any other bytes, as they're for undefined bits.
1897 for (i = 0; i < ARRAY_SIZE(reason_map); i++)
1899 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1901 bytesNeeded += lstrlenW(reason_map[i].reason) * sizeof(WCHAR);
1902 if (numReasons++)
1903 bytesNeeded += lstrlenW(sep) * sizeof(WCHAR);
1906 swprintf(bits, ARRAY_SIZE(bits), L" (%02x)", reasonFlags->pbData[0]);
1907 bytesNeeded += lstrlenW(bits);
1908 if (!str)
1909 *pcbStr = bytesNeeded;
1910 else if (*pcbStr < bytesNeeded)
1912 *pcbStr = bytesNeeded;
1913 SetLastError(ERROR_MORE_DATA);
1914 ret = FALSE;
1916 else
1918 *pcbStr = bytesNeeded;
1919 for (i = 0; i < ARRAY_SIZE(reason_map); i++)
1921 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1923 lstrcpyW(str, reason_map[i].reason);
1924 str += lstrlenW(reason_map[i].reason);
1925 if (i < ARRAY_SIZE(reason_map) - 1 && numReasons)
1927 lstrcpyW(str, sep);
1928 str += lstrlenW(sep);
1932 lstrcpyW(str, bits);
1934 return ret;
1937 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1938 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1939 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1940 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1941 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1942 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1944 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1945 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1946 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1947 DWORD *pcbFormat)
1949 CRL_DIST_POINTS_INFO *info;
1950 DWORD size;
1951 BOOL ret = FALSE;
1953 if (!cbEncoded)
1955 SetLastError(E_INVALIDARG);
1956 return FALSE;
1958 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1959 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1961 static const WCHAR colon[] = L":";
1962 static BOOL stringsLoaded = FALSE;
1963 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1964 BOOL haveAnEntry = FALSE;
1965 LPCWSTR headingSep, nameSep;
1966 WCHAR distPointNum[11];
1967 DWORD i;
1969 if (!stringsLoaded)
1971 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint, ARRAY_SIZE(crlDistPoint));
1972 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName, ARRAY_SIZE(distPointName));
1973 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName, ARRAY_SIZE(fullName));
1974 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName, ARRAY_SIZE(rdnName));
1975 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason, ARRAY_SIZE(reason));
1976 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer, ARRAY_SIZE(issuer));
1977 stringsLoaded = TRUE;
1979 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1981 headingSep = crlf;
1982 nameSep = colonCrlf;
1984 else
1986 headingSep = colonSep;
1987 nameSep = colon;
1990 for (i = 0; ret && i < info->cDistPoint; i++)
1992 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1994 if (distPoint->DistPointName.dwDistPointNameChoice !=
1995 CRL_DIST_POINT_NO_NAME)
1997 bytesNeeded += lstrlenW(distPointName) * sizeof(WCHAR);
1998 bytesNeeded += lstrlenW(nameSep) * sizeof(WCHAR);
1999 if (distPoint->DistPointName.dwDistPointNameChoice ==
2000 CRL_DIST_POINT_FULL_NAME)
2001 bytesNeeded += lstrlenW(fullName) * sizeof(WCHAR);
2002 else
2003 bytesNeeded += lstrlenW(rdnName) * sizeof(WCHAR);
2004 bytesNeeded += lstrlenW(nameSep) * sizeof(WCHAR);
2005 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2006 bytesNeeded += 2 * lstrlenW(indent) * sizeof(WCHAR);
2007 /* The indent level (3) is higher than when used as the issuer,
2008 * because the name is subordinate to the name type (full vs.
2009 * RDN.)
2011 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2012 &distPoint->DistPointName.u.FullName, NULL, &size);
2013 if (ret)
2014 bytesNeeded += size - sizeof(WCHAR);
2015 haveAnEntry = TRUE;
2017 else if (distPoint->ReasonFlags.cbData)
2019 bytesNeeded += lstrlenW(reason) * sizeof(WCHAR);
2020 ret = CRYPT_FormatReason(dwFormatStrType,
2021 &distPoint->ReasonFlags, NULL, &size);
2022 if (ret)
2023 bytesNeeded += size - sizeof(WCHAR);
2024 haveAnEntry = TRUE;
2026 else if (distPoint->CRLIssuer.cAltEntry)
2028 bytesNeeded += lstrlenW(issuer) * sizeof(WCHAR);
2029 bytesNeeded += lstrlenW(nameSep) * sizeof(WCHAR);
2030 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2031 &distPoint->CRLIssuer, NULL, &size);
2032 if (ret)
2033 bytesNeeded += size - sizeof(WCHAR);
2034 haveAnEntry = TRUE;
2036 if (haveAnEntry)
2038 bytesNeeded += sizeof(WCHAR); /* left bracket */
2039 swprintf(distPointNum, ARRAY_SIZE(distPointNum), L"%d", i + 1);
2040 bytesNeeded += lstrlenW(distPointNum) * sizeof(WCHAR);
2041 bytesNeeded += sizeof(WCHAR); /* right bracket */
2042 bytesNeeded += lstrlenW(crlDistPoint) * sizeof(WCHAR);
2043 bytesNeeded += lstrlenW(headingSep) * sizeof(WCHAR);
2044 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2045 bytesNeeded += lstrlenW(indent) * sizeof(WCHAR);
2048 if (!haveAnEntry)
2050 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2052 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
2053 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
2054 if (!pbFormat)
2055 *pcbFormat = bytesNeeded;
2056 else if (*pcbFormat < bytesNeeded)
2058 *pcbFormat = bytesNeeded;
2059 SetLastError(ERROR_MORE_DATA);
2060 ret = FALSE;
2062 else
2064 *pcbFormat = bytesNeeded;
2065 lstrcpyW(pbFormat, infoNotAvailable);
2068 else
2070 if (!pbFormat)
2071 *pcbFormat = bytesNeeded;
2072 else if (*pcbFormat < bytesNeeded)
2074 *pcbFormat = bytesNeeded;
2075 SetLastError(ERROR_MORE_DATA);
2076 ret = FALSE;
2078 else
2080 LPWSTR str = pbFormat;
2082 *pcbFormat = bytesNeeded;
2083 for (i = 0; ret && i < info->cDistPoint; i++)
2085 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2087 *str++ = '[';
2088 swprintf(distPointNum, ARRAY_SIZE(distPointNum), L"%d", i + 1);
2089 lstrcpyW(str, distPointNum);
2090 str += lstrlenW(distPointNum);
2091 *str++ = ']';
2092 lstrcpyW(str, crlDistPoint);
2093 str += lstrlenW(crlDistPoint);
2094 lstrcpyW(str, headingSep);
2095 str += lstrlenW(headingSep);
2096 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2098 lstrcpyW(str, indent);
2099 str += lstrlenW(indent);
2101 if (distPoint->DistPointName.dwDistPointNameChoice !=
2102 CRL_DIST_POINT_NO_NAME)
2104 DWORD altNameSize = bytesNeeded;
2106 lstrcpyW(str, distPointName);
2107 str += lstrlenW(distPointName);
2108 lstrcpyW(str, nameSep);
2109 str += lstrlenW(nameSep);
2110 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2112 lstrcpyW(str, indent);
2113 str += lstrlenW(indent);
2114 lstrcpyW(str, indent);
2115 str += lstrlenW(indent);
2117 if (distPoint->DistPointName.dwDistPointNameChoice ==
2118 CRL_DIST_POINT_FULL_NAME)
2120 lstrcpyW(str, fullName);
2121 str += lstrlenW(fullName);
2123 else
2125 lstrcpyW(str, rdnName);
2126 str += lstrlenW(rdnName);
2128 lstrcpyW(str, nameSep);
2129 str += lstrlenW(nameSep);
2130 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2131 &distPoint->DistPointName.u.FullName, str,
2132 &altNameSize);
2133 if (ret)
2134 str += altNameSize / sizeof(WCHAR) - 1;
2136 else if (distPoint->ReasonFlags.cbData)
2138 DWORD reasonSize = bytesNeeded;
2140 lstrcpyW(str, reason);
2141 str += lstrlenW(reason);
2142 ret = CRYPT_FormatReason(dwFormatStrType,
2143 &distPoint->ReasonFlags, str, &reasonSize);
2144 if (ret)
2145 str += reasonSize / sizeof(WCHAR) - 1;
2147 else if (distPoint->CRLIssuer.cAltEntry)
2149 DWORD crlIssuerSize = bytesNeeded;
2151 lstrcpyW(str, issuer);
2152 str += lstrlenW(issuer);
2153 lstrcpyW(str, nameSep);
2154 str += lstrlenW(nameSep);
2155 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2156 &distPoint->CRLIssuer, str,
2157 &crlIssuerSize);
2158 if (ret)
2159 str += crlIssuerSize / sizeof(WCHAR) - 1;
2164 LocalFree(info);
2166 return ret;
2169 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2170 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2171 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2172 DWORD *pcbFormat)
2174 CERT_ENHKEY_USAGE *usage;
2175 DWORD size;
2176 BOOL ret = FALSE;
2178 if (!cbEncoded)
2180 SetLastError(E_INVALIDARG);
2181 return FALSE;
2183 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2184 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2186 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2187 DWORD i;
2188 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2189 LPCWSTR sep;
2190 DWORD sepLen;
2192 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2194 sep = crlf;
2195 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
2197 else
2199 sep = commaSpace;
2200 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
2203 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown, ARRAY_SIZE(unknown));
2204 for (i = 0; i < usage->cUsageIdentifier; i++)
2206 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2207 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2209 if (info)
2210 bytesNeeded += lstrlenW(info->pwszName) * sizeof(WCHAR);
2211 else
2212 bytesNeeded += lstrlenW(unknown) * sizeof(WCHAR);
2213 bytesNeeded += sizeof(WCHAR); /* space */
2214 bytesNeeded += sizeof(WCHAR); /* left paren */
2215 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
2216 sizeof(WCHAR);
2217 bytesNeeded += sizeof(WCHAR); /* right paren */
2218 if (i < usage->cUsageIdentifier - 1)
2219 bytesNeeded += sepLen;
2221 if (!pbFormat)
2222 *pcbFormat = bytesNeeded;
2223 else if (*pcbFormat < bytesNeeded)
2225 *pcbFormat = bytesNeeded;
2226 SetLastError(ERROR_MORE_DATA);
2227 ret = FALSE;
2229 else
2231 LPWSTR str = pbFormat;
2233 *pcbFormat = bytesNeeded;
2234 for (i = 0; i < usage->cUsageIdentifier; i++)
2236 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2237 usage->rgpszUsageIdentifier[i],
2238 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2239 LPCSTR oidPtr;
2241 if (info)
2243 lstrcpyW(str, info->pwszName);
2244 str += lstrlenW(info->pwszName);
2246 else
2248 lstrcpyW(str, unknown);
2249 str += lstrlenW(unknown);
2251 *str++ = ' ';
2252 *str++ = '(';
2253 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2254 *str++ = *oidPtr;
2255 *str++ = ')';
2256 *str = 0;
2257 if (i < usage->cUsageIdentifier - 1)
2259 lstrcpyW(str, sep);
2260 str += sepLen / sizeof(WCHAR);
2264 LocalFree(usage);
2266 return ret;
2269 static struct BitToString netscapeCertTypeMap[] = {
2270 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2271 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2272 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2273 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2274 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2275 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2276 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2279 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2280 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2281 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2282 DWORD *pcbFormat)
2284 DWORD size;
2285 CRYPT_BIT_BLOB *bits;
2286 BOOL ret;
2288 if (!cbEncoded)
2290 SetLastError(E_INVALIDARG);
2291 return FALSE;
2293 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2294 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2296 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2297 DWORD bytesNeeded = sizeof(WCHAR);
2299 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, ARRAY_SIZE(infoNotAvailable));
2300 if (!bits->cbData || bits->cbData > 1)
2302 bytesNeeded += lstrlenW(infoNotAvailable) * sizeof(WCHAR);
2303 if (!pbFormat)
2304 *pcbFormat = bytesNeeded;
2305 else if (*pcbFormat < bytesNeeded)
2307 *pcbFormat = bytesNeeded;
2308 SetLastError(ERROR_MORE_DATA);
2309 ret = FALSE;
2311 else
2313 LPWSTR str = pbFormat;
2315 *pcbFormat = bytesNeeded;
2316 lstrcpyW(str, infoNotAvailable);
2319 else
2321 static BOOL stringsLoaded = FALSE;
2322 unsigned int i;
2323 DWORD bitStringLen;
2324 BOOL first = TRUE;
2326 if (!stringsLoaded)
2328 for (i = 0; i < ARRAY_SIZE(netscapeCertTypeMap); i++)
2329 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2330 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2331 stringsLoaded = TRUE;
2333 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, ARRAY_SIZE(netscapeCertTypeMap),
2334 NULL, &bitStringLen, &first);
2335 bytesNeeded += bitStringLen;
2336 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2337 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2338 bits->cbData, NULL, &size);
2339 bytesNeeded += size;
2340 if (!pbFormat)
2341 *pcbFormat = bytesNeeded;
2342 else if (*pcbFormat < bytesNeeded)
2344 *pcbFormat = bytesNeeded;
2345 SetLastError(ERROR_MORE_DATA);
2346 ret = FALSE;
2348 else
2350 LPWSTR str = pbFormat;
2352 bitStringLen = bytesNeeded;
2353 first = TRUE;
2354 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, ARRAY_SIZE(netscapeCertTypeMap),
2355 str, &bitStringLen, &first);
2356 str += bitStringLen / sizeof(WCHAR) - 1;
2357 *str++ = ' ';
2358 *str++ = '(';
2359 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2360 bits->cbData, str, &size);
2361 str += size / sizeof(WCHAR) - 1;
2362 *str++ = ')';
2363 *str = 0;
2366 LocalFree(bits);
2368 return ret;
2371 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2372 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2373 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2374 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2375 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2376 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2378 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2379 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2380 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2381 DWORD *pcbFormat)
2383 SPC_FINANCIAL_CRITERIA criteria;
2384 DWORD size = sizeof(criteria);
2385 BOOL ret = FALSE;
2387 if (!cbEncoded)
2389 SetLastError(E_INVALIDARG);
2390 return FALSE;
2392 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2393 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2394 &size)))
2396 static BOOL stringsLoaded = FALSE;
2397 DWORD bytesNeeded = sizeof(WCHAR);
2398 LPCWSTR sep;
2399 DWORD sepLen;
2401 if (!stringsLoaded)
2403 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria, ARRAY_SIZE(financialCriteria));
2404 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available, ARRAY_SIZE(available));
2405 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE, notAvailable, ARRAY_SIZE(notAvailable));
2406 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA, meetsCriteria, ARRAY_SIZE(meetsCriteria));
2407 LoadStringW(hInstance, IDS_YES, yes, ARRAY_SIZE(yes));
2408 LoadStringW(hInstance, IDS_NO, no, ARRAY_SIZE(no));
2409 stringsLoaded = TRUE;
2411 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2413 sep = crlf;
2414 sepLen = lstrlenW(crlf) * sizeof(WCHAR);
2416 else
2418 sep = commaSpace;
2419 sepLen = lstrlenW(commaSpace) * sizeof(WCHAR);
2421 bytesNeeded += lstrlenW(financialCriteria) * sizeof(WCHAR);
2422 if (criteria.fFinancialInfoAvailable)
2424 bytesNeeded += lstrlenW(available) * sizeof(WCHAR);
2425 bytesNeeded += sepLen;
2426 bytesNeeded += lstrlenW(meetsCriteria) * sizeof(WCHAR);
2427 if (criteria.fMeetsCriteria)
2428 bytesNeeded += lstrlenW(yes) * sizeof(WCHAR);
2429 else
2430 bytesNeeded += lstrlenW(no) * sizeof(WCHAR);
2432 else
2433 bytesNeeded += lstrlenW(notAvailable) * sizeof(WCHAR);
2434 if (!pbFormat)
2435 *pcbFormat = bytesNeeded;
2436 else if (*pcbFormat < bytesNeeded)
2438 *pcbFormat = bytesNeeded;
2439 SetLastError(ERROR_MORE_DATA);
2440 ret = FALSE;
2442 else
2444 LPWSTR str = pbFormat;
2446 *pcbFormat = bytesNeeded;
2447 lstrcpyW(str, financialCriteria);
2448 str += lstrlenW(financialCriteria);
2449 if (criteria.fFinancialInfoAvailable)
2451 lstrcpyW(str, available);
2452 str += lstrlenW(available);
2453 lstrcpyW(str, sep);
2454 str += sepLen / sizeof(WCHAR);
2455 lstrcpyW(str, meetsCriteria);
2456 str += lstrlenW(meetsCriteria);
2457 if (criteria.fMeetsCriteria)
2458 lstrcpyW(str, yes);
2459 else
2460 lstrcpyW(str, no);
2462 else
2464 lstrcpyW(str, notAvailable);
2468 return ret;
2471 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2472 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2473 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2474 DWORD *pcbFormat)
2476 CERT_NAME_VALUE *value;
2477 DWORD size;
2478 BOOL ret;
2480 if (!cbEncoded)
2482 SetLastError(E_INVALIDARG);
2483 return FALSE;
2485 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2486 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2488 if (!pbFormat)
2489 *pcbFormat = value->Value.cbData;
2490 else if (*pcbFormat < value->Value.cbData)
2492 *pcbFormat = value->Value.cbData;
2493 SetLastError(ERROR_MORE_DATA);
2494 ret = FALSE;
2496 else
2498 LPWSTR str = pbFormat;
2500 *pcbFormat = value->Value.cbData;
2501 lstrcpyW(str, (LPWSTR)value->Value.pbData);
2504 return ret;
2507 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2508 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2510 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2511 DWORD formatStrType, LPCSTR lpszStructType)
2513 CryptFormatObjectFunc format = NULL;
2515 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2517 SetLastError(ERROR_FILE_NOT_FOUND);
2518 return NULL;
2520 if (IS_INTOID(lpszStructType))
2522 switch (LOWORD(lpszStructType))
2524 case LOWORD(X509_KEY_USAGE):
2525 format = CRYPT_FormatKeyUsage;
2526 break;
2527 case LOWORD(X509_ALTERNATE_NAME):
2528 format = CRYPT_FormatAltName;
2529 break;
2530 case LOWORD(X509_BASIC_CONSTRAINTS2):
2531 format = CRYPT_FormatBasicConstraints2;
2532 break;
2533 case LOWORD(X509_AUTHORITY_KEY_ID2):
2534 format = CRYPT_FormatAuthorityKeyId2;
2535 break;
2536 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2537 format = CRYPT_FormatAuthorityInfoAccess;
2538 break;
2539 case LOWORD(X509_CRL_DIST_POINTS):
2540 format = CRYPT_FormatCRLDistPoints;
2541 break;
2542 case LOWORD(X509_ENHANCED_KEY_USAGE):
2543 format = CRYPT_FormatEnhancedKeyUsage;
2544 break;
2545 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2546 format = CRYPT_FormatSpcFinancialCriteria;
2547 break;
2550 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2551 format = CRYPT_FormatAltName;
2552 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2553 format = CRYPT_FormatAltName;
2554 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2555 format = CRYPT_FormatKeyUsage;
2556 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2557 format = CRYPT_FormatAltName;
2558 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2559 format = CRYPT_FormatAltName;
2560 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2561 format = CRYPT_FormatBasicConstraints2;
2562 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2563 format = CRYPT_FormatAuthorityInfoAccess;
2564 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2565 format = CRYPT_FormatAuthorityKeyId2;
2566 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2567 format = CRYPT_FormatCRLDistPoints;
2568 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2569 format = CRYPT_FormatEnhancedKeyUsage;
2570 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2571 format = CRYPT_FormatNetscapeCertType;
2572 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2573 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2574 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2575 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2576 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2577 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2578 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2579 format = CRYPT_FormatUnicodeString;
2580 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2581 format = CRYPT_FormatSpcFinancialCriteria;
2582 return format;
2585 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2586 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2587 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2589 CryptFormatObjectFunc format = NULL;
2590 HCRYPTOIDFUNCADDR hFunc = NULL;
2591 BOOL ret = FALSE;
2593 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2594 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2595 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2597 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2598 dwFormatStrType, lpszStructType)))
2600 static HCRYPTOIDFUNCSET set = NULL;
2602 if (!set)
2603 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2604 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2605 (void **)&format, &hFunc);
2607 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2608 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2609 format = CRYPT_FormatHexString;
2610 if (format)
2611 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2612 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2613 pcbFormat);
2614 if (hFunc)
2615 CryptFreeOIDFunctionAddress(hFunc, 0);
2616 return ret;