crypt32: Use Context_Release instead of WINE_CONTEXT_INTERFACE.
[wine.git] / dlls / crypt32 / object.c
blob0ff1bfd0cbd00bef4cddc76c12013f632220aa1b
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/unicode.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
35 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
37 BOOL ret = FALSE;
38 HANDLE file;
40 TRACE("%s\n", debugstr_w(fileName));
42 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
43 OPEN_EXISTING, 0, NULL);
44 if (file != INVALID_HANDLE_VALUE)
46 ret = TRUE;
47 blob->cbData = GetFileSize(file, NULL);
48 if (blob->cbData)
50 blob->pbData = CryptMemAlloc(blob->cbData);
51 if (blob->pbData)
53 DWORD read;
55 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
58 CloseHandle(file);
60 TRACE("returning %d\n", ret);
61 return ret;
64 static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
65 DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
66 DWORD *contentType, const void **ppvContext)
68 BOOL ret = FALSE;
70 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
72 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
73 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
74 if (ret && contentType)
75 *contentType = CERT_QUERY_CONTENT_CERT;
77 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
79 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
80 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
81 if (ret && contentType)
82 *contentType = CERT_QUERY_CONTENT_CRL;
84 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
86 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
87 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
88 if (ret && contentType)
89 *contentType = CERT_QUERY_CONTENT_CTL;
91 return ret;
94 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
95 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
96 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
97 HCERTSTORE *phCertStore, const void **ppvContext)
99 CERT_BLOB fileBlob;
100 const CERT_BLOB *blob;
101 HCERTSTORE store;
102 BOOL ret;
103 DWORD formatType = 0;
105 switch (dwObjectType)
107 case CERT_QUERY_OBJECT_FILE:
108 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
109 * just read the file directly
111 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
112 blob = &fileBlob;
113 break;
114 case CERT_QUERY_OBJECT_BLOB:
115 blob = pvObject;
116 ret = TRUE;
117 break;
118 default:
119 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
120 ret = FALSE;
122 if (!ret)
123 return FALSE;
125 ret = FALSE;
126 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
127 CERT_STORE_CREATE_NEW_FLAG, NULL);
128 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
130 ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
131 pdwContentType, ppvContext);
132 if (ret)
133 formatType = CERT_QUERY_FORMAT_BINARY;
135 if (!ret &&
136 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
138 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
139 CRYPT_DATA_BLOB decoded;
141 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
142 trimmed.cbData--;
143 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
144 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
145 if (ret)
147 decoded.pbData = CryptMemAlloc(decoded.cbData);
148 if (decoded.pbData)
150 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
151 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
152 &decoded.cbData, NULL, NULL);
153 if (ret)
155 ret = CRYPT_QueryContextBlob(&decoded,
156 dwExpectedContentTypeFlags, store, pdwContentType,
157 ppvContext);
158 if (ret)
159 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
161 CryptMemFree(decoded.pbData);
163 else
164 ret = FALSE;
167 if (ret)
169 if (pdwMsgAndCertEncodingType)
170 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
171 if (pdwFormatType)
172 *pdwFormatType = formatType;
173 if (phCertStore)
174 *phCertStore = CertDuplicateStore(store);
176 CertCloseStore(store, 0);
177 if (blob == &fileBlob)
178 CryptMemFree(blob->pbData);
179 TRACE("returning %d\n", ret);
180 return ret;
183 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
184 const void *pvObject, DWORD dwExpectedContentTypeFlags,
185 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
186 HCERTSTORE *phCertStore, const void **ppvContext)
188 CERT_BLOB fileBlob;
189 const CERT_BLOB *blob;
190 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
191 const void *context;
192 DWORD contextType;
193 BOOL ret;
195 switch (dwObjectType)
197 case CERT_QUERY_OBJECT_FILE:
198 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
199 * just read the file directly
201 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
202 blob = &fileBlob;
203 break;
204 case CERT_QUERY_OBJECT_BLOB:
205 blob = pvObject;
206 ret = TRUE;
207 break;
208 default:
209 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
210 ret = FALSE;
212 if (!ret)
213 return FALSE;
215 ret = FALSE;
216 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
217 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
218 if (context)
220 DWORD contentType, certStoreOffset;
222 ret = TRUE;
223 switch (contextType)
225 case CERT_STORE_CERTIFICATE_CONTEXT:
226 contextInterface = pCertInterface;
227 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
228 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
229 if (!(dwExpectedContentTypeFlags &
230 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
232 SetLastError(ERROR_INVALID_DATA);
233 ret = FALSE;
234 goto end;
236 break;
237 case CERT_STORE_CRL_CONTEXT:
238 contextInterface = pCRLInterface;
239 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
240 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
241 if (!(dwExpectedContentTypeFlags &
242 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
244 SetLastError(ERROR_INVALID_DATA);
245 ret = FALSE;
246 goto end;
248 break;
249 case CERT_STORE_CTL_CONTEXT:
250 contextInterface = pCTLInterface;
251 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
252 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
253 if (!(dwExpectedContentTypeFlags &
254 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
256 SetLastError(ERROR_INVALID_DATA);
257 ret = FALSE;
258 goto end;
260 break;
261 default:
262 SetLastError(ERROR_INVALID_DATA);
263 ret = FALSE;
264 goto end;
266 if (pdwMsgAndCertEncodingType)
267 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
268 if (pdwContentType)
269 *pdwContentType = contentType;
270 if (phCertStore)
271 *phCertStore = CertDuplicateStore(
272 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
273 if (ppvContext)
275 *ppvContext = context;
276 Context_AddRef(context_from_ptr(context));
280 end:
281 if (contextInterface && context)
282 Context_Release(context_from_ptr(context));
283 if (blob == &fileBlob)
284 CryptMemFree(blob->pbData);
285 TRACE("returning %d\n", ret);
286 return ret;
289 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
290 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
291 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
293 HANDLE file;
294 BOOL ret = FALSE;
296 TRACE("%s\n", debugstr_w(fileName));
297 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
298 OPEN_EXISTING, 0, NULL);
299 if (file != INVALID_HANDLE_VALUE)
301 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
302 CERT_STORE_CREATE_NEW_FLAG, NULL);
304 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
305 if (ret)
307 if (pdwMsgAndCertEncodingType)
308 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
309 if (pdwContentType)
310 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
311 if (phCertStore)
312 *phCertStore = CertDuplicateStore(store);
314 CertCloseStore(store, 0);
315 CloseHandle(file);
317 TRACE("returning %d\n", ret);
318 return ret;
321 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
322 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
323 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
325 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
326 CERT_STORE_CREATE_NEW_FLAG, NULL);
327 BOOL ret;
329 TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
331 ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
332 if (ret)
334 if (pdwMsgAndCertEncodingType)
335 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
336 if (pdwContentType)
337 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
338 if (phCertStore)
339 *phCertStore = CertDuplicateStore(store);
341 CertCloseStore(store, 0);
342 TRACE("returning %d\n", ret);
343 return ret;
346 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
347 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
348 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
350 switch (dwObjectType)
352 case CERT_QUERY_OBJECT_FILE:
353 return CRYPT_QuerySerializedStoreFromFile(pvObject,
354 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
355 case CERT_QUERY_OBJECT_BLOB:
356 return CRYPT_QuerySerializedStoreFromBlob(pvObject,
357 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
358 default:
359 FIXME("unimplemented for type %d\n", dwObjectType);
360 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
361 return FALSE;
365 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
366 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
368 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
369 BOOL ret = FALSE;
370 HCRYPTMSG msg;
372 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
374 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
375 if (ret)
377 DWORD type, len = sizeof(type);
379 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
380 if (ret)
382 if (type != CMSG_SIGNED)
384 SetLastError(ERROR_INVALID_DATA);
385 ret = FALSE;
389 if (!ret)
391 CryptMsgClose(msg);
392 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
393 NULL);
394 if (msg)
396 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
397 if (!ret)
399 CryptMsgClose(msg);
400 msg = NULL;
405 if (ret)
407 if (pdwMsgAndCertEncodingType)
408 *pdwMsgAndCertEncodingType = encodingType;
409 if (pdwContentType)
410 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
411 if (phMsg)
412 *phMsg = msg;
414 return ret;
417 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
418 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
420 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
421 BOOL ret = FALSE;
422 HCRYPTMSG msg;
424 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
426 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
427 if (ret)
429 DWORD type, len = sizeof(type);
431 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
432 if (ret)
434 if (type != CMSG_DATA)
436 SetLastError(ERROR_INVALID_DATA);
437 ret = FALSE;
441 if (!ret)
443 CryptMsgClose(msg);
444 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
445 NULL, NULL);
446 if (msg)
448 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
449 if (!ret)
451 CryptMsgClose(msg);
452 msg = NULL;
457 if (ret)
459 if (pdwMsgAndCertEncodingType)
460 *pdwMsgAndCertEncodingType = encodingType;
461 if (pdwContentType)
462 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
463 if (phMsg)
464 *phMsg = msg;
466 return ret;
469 /* Used to decode non-embedded messages */
470 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
471 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
472 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
473 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
475 CERT_BLOB fileBlob;
476 const CERT_BLOB *blob;
477 BOOL ret;
478 HCRYPTMSG msg = NULL;
479 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
480 DWORD formatType = 0;
482 TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
483 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
484 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
485 phMsg);
487 switch (dwObjectType)
489 case CERT_QUERY_OBJECT_FILE:
490 /* This isn't an embedded PKCS7 message, so just read the file
491 * directly
493 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
494 blob = &fileBlob;
495 break;
496 case CERT_QUERY_OBJECT_BLOB:
497 blob = pvObject;
498 ret = TRUE;
499 break;
500 default:
501 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
502 ret = FALSE;
504 if (!ret)
505 return FALSE;
507 ret = FALSE;
508 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
510 /* Try it first as a signed message */
511 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
512 ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
513 pdwContentType, &msg);
514 /* Failing that, try as an unsigned message */
515 if (!ret &&
516 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
517 ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
518 pdwContentType, &msg);
519 if (ret)
520 formatType = CERT_QUERY_FORMAT_BINARY;
522 if (!ret &&
523 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
525 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
526 CRYPT_DATA_BLOB decoded;
528 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
529 trimmed.cbData--;
530 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
531 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
532 if (ret)
534 decoded.pbData = CryptMemAlloc(decoded.cbData);
535 if (decoded.pbData)
537 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
538 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
539 &decoded.cbData, NULL, NULL);
540 if (ret)
542 /* Try it first as a signed message */
543 if (dwExpectedContentTypeFlags &
544 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
545 ret = CRYPT_QuerySignedMessage(&decoded,
546 pdwMsgAndCertEncodingType, pdwContentType, &msg);
547 /* Failing that, try as an unsigned message */
548 if (!ret && (dwExpectedContentTypeFlags &
549 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
550 ret = CRYPT_QueryUnsignedMessage(&decoded,
551 pdwMsgAndCertEncodingType, pdwContentType, &msg);
552 if (ret)
553 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
555 CryptMemFree(decoded.pbData);
557 else
558 ret = FALSE;
560 if (!ret && !(blob->cbData % sizeof(WCHAR)))
562 CRYPT_DATA_BLOB decoded;
563 LPWSTR str = (LPWSTR)blob->pbData;
564 DWORD strLen = blob->cbData / sizeof(WCHAR);
566 /* Try again, assuming the input string is UTF-16 base64 */
567 while (strLen && !str[strLen - 1])
568 strLen--;
569 ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
570 NULL, &decoded.cbData, NULL, NULL);
571 if (ret)
573 decoded.pbData = CryptMemAlloc(decoded.cbData);
574 if (decoded.pbData)
576 ret = CryptStringToBinaryW(str, strLen,
577 CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
578 NULL, NULL);
579 if (ret)
581 /* Try it first as a signed message */
582 if (dwExpectedContentTypeFlags &
583 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
584 ret = CRYPT_QuerySignedMessage(&decoded,
585 pdwMsgAndCertEncodingType, pdwContentType, &msg);
586 /* Failing that, try as an unsigned message */
587 if (!ret && (dwExpectedContentTypeFlags &
588 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
589 ret = CRYPT_QueryUnsignedMessage(&decoded,
590 pdwMsgAndCertEncodingType, pdwContentType, &msg);
591 if (ret)
592 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
594 CryptMemFree(decoded.pbData);
596 else
597 ret = FALSE;
601 if (ret)
603 if (pdwFormatType)
604 *pdwFormatType = formatType;
605 if (phCertStore)
606 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
607 0, msg);
608 if (phMsg)
609 *phMsg = msg;
610 else
611 CryptMsgClose(msg);
613 if (blob == &fileBlob)
614 CryptMemFree(blob->pbData);
615 TRACE("returning %d\n", ret);
616 return ret;
619 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
620 const void *pvObject, DWORD dwExpectedContentTypeFlags,
621 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
622 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
624 HANDLE file;
625 GUID subject;
626 BOOL ret = FALSE;
628 TRACE("%s\n", debugstr_w(pvObject));
630 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
632 WARN("don't know what to do for type %d embedded signed messages\n",
633 dwObjectType);
634 SetLastError(E_INVALIDARG);
635 return FALSE;
637 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
638 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
639 if (file != INVALID_HANDLE_VALUE)
641 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
642 if (ret)
644 SIP_DISPATCH_INFO sip;
646 memset(&sip, 0, sizeof(sip));
647 sip.cbSize = sizeof(sip);
648 ret = CryptSIPLoad(&subject, 0, &sip);
649 if (ret)
651 SIP_SUBJECTINFO subjectInfo;
652 CERT_BLOB blob;
653 DWORD encodingType;
655 memset(&subjectInfo, 0, sizeof(subjectInfo));
656 subjectInfo.cbSize = sizeof(subjectInfo);
657 subjectInfo.pgSubjectType = &subject;
658 subjectInfo.hFile = file;
659 subjectInfo.pwsFileName = pvObject;
660 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
661 NULL);
662 if (ret)
664 blob.pbData = CryptMemAlloc(blob.cbData);
665 if (blob.pbData)
667 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
668 &blob.cbData, blob.pbData);
669 if (ret)
671 ret = CRYPT_QueryMessageObject(
672 CERT_QUERY_OBJECT_BLOB, &blob,
673 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
674 CERT_QUERY_FORMAT_FLAG_BINARY,
675 pdwMsgAndCertEncodingType, NULL, NULL,
676 phCertStore, phMsg);
677 if (ret && pdwContentType)
678 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
680 CryptMemFree(blob.pbData);
682 else
684 SetLastError(ERROR_OUTOFMEMORY);
685 ret = FALSE;
690 CloseHandle(file);
692 TRACE("returning %d\n", ret);
693 return ret;
696 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
697 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
698 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
699 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
700 const void **ppvContext)
702 static const DWORD unimplementedTypes =
703 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
704 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
705 BOOL ret = TRUE;
707 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
708 dwObjectType, pvObject, dwExpectedContentTypeFlags,
709 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
710 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
712 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
713 dwObjectType != CERT_QUERY_OBJECT_FILE)
715 WARN("unsupported type %d\n", dwObjectType);
716 SetLastError(E_INVALIDARG);
717 return FALSE;
719 if (!pvObject)
721 WARN("missing required argument\n");
722 SetLastError(E_INVALIDARG);
723 return FALSE;
725 if (dwExpectedContentTypeFlags & unimplementedTypes)
726 WARN("unimplemented for types %08x\n",
727 dwExpectedContentTypeFlags & unimplementedTypes);
729 if (pdwFormatType)
730 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
731 if (phCertStore)
732 *phCertStore = NULL;
733 if (phMsg)
734 *phMsg = NULL;
735 if (ppvContext)
736 *ppvContext = NULL;
738 ret = FALSE;
739 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
740 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
741 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
743 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
744 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
745 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
746 ppvContext);
748 if (!ret &&
749 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
751 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
752 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
754 if (!ret &&
755 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
756 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
757 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
759 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
760 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
761 phCertStore, ppvContext);
763 if (!ret &&
764 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
765 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
767 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
768 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
769 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
770 phCertStore, phMsg);
772 if (!ret &&
773 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
775 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
776 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
777 phCertStore, phMsg);
779 if (!ret)
780 SetLastError(CRYPT_E_NO_MATCH);
781 TRACE("returning %d\n", ret);
782 return ret;
785 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
786 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
787 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
788 DWORD *pcbFormat)
790 BOOL ret;
791 DWORD bytesNeeded;
793 if (cbEncoded)
794 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
795 else
796 bytesNeeded = sizeof(WCHAR);
797 if (!pbFormat)
799 *pcbFormat = bytesNeeded;
800 ret = TRUE;
802 else if (*pcbFormat < bytesNeeded)
804 *pcbFormat = bytesNeeded;
805 SetLastError(ERROR_MORE_DATA);
806 ret = FALSE;
808 else
810 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
811 static const WCHAR endFmt[] = { '%','0','2','x',0 };
812 DWORD i;
813 LPWSTR ptr = pbFormat;
815 *pcbFormat = bytesNeeded;
816 if (cbEncoded)
818 for (i = 0; i < cbEncoded; i++)
820 if (i < cbEncoded - 1)
821 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
822 else
823 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
826 else
827 *ptr = 0;
828 ret = TRUE;
830 return ret;
833 #define MAX_STRING_RESOURCE_LEN 128
835 static const WCHAR commaSpace[] = { ',',' ',0 };
837 struct BitToString
839 BYTE bit;
840 int id;
841 WCHAR str[MAX_STRING_RESOURCE_LEN];
844 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
845 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
847 DWORD bytesNeeded = sizeof(WCHAR);
848 unsigned int i;
849 BOOL ret = TRUE, localFirst = *first;
851 for (i = 0; i < mapEntries; i++)
852 if (bits & map[i].bit)
854 if (!localFirst)
855 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
856 localFirst = FALSE;
857 bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
859 if (!pbFormat)
861 *first = localFirst;
862 *pcbFormat = bytesNeeded;
864 else if (*pcbFormat < bytesNeeded)
866 *first = localFirst;
867 *pcbFormat = bytesNeeded;
868 SetLastError(ERROR_MORE_DATA);
869 ret = FALSE;
871 else
873 LPWSTR str = pbFormat;
875 localFirst = *first;
876 *pcbFormat = bytesNeeded;
877 for (i = 0; i < mapEntries; i++)
878 if (bits & map[i].bit)
880 if (!localFirst)
882 strcpyW(str, commaSpace);
883 str += strlenW(commaSpace);
885 localFirst = FALSE;
886 strcpyW(str, map[i].str);
887 str += strlenW(map[i].str);
889 *first = localFirst;
891 return ret;
894 static struct BitToString keyUsageByte0Map[] = {
895 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
896 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
897 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
898 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
899 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
900 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
901 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
902 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
903 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
905 static struct BitToString keyUsageByte1Map[] = {
906 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
909 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
910 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
911 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
912 DWORD *pcbFormat)
914 DWORD size;
915 CRYPT_BIT_BLOB *bits;
916 BOOL ret;
918 if (!cbEncoded)
920 SetLastError(E_INVALIDARG);
921 return FALSE;
923 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
924 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
926 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
927 DWORD bytesNeeded = sizeof(WCHAR);
929 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
930 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
931 if (!bits->cbData || bits->cbData > 2)
933 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
934 if (!pbFormat)
935 *pcbFormat = bytesNeeded;
936 else if (*pcbFormat < bytesNeeded)
938 *pcbFormat = bytesNeeded;
939 SetLastError(ERROR_MORE_DATA);
940 ret = FALSE;
942 else
944 LPWSTR str = pbFormat;
946 *pcbFormat = bytesNeeded;
947 strcpyW(str, infoNotAvailable);
950 else
952 static BOOL stringsLoaded = FALSE;
953 unsigned int i;
954 DWORD bitStringLen;
955 BOOL first = TRUE;
957 if (!stringsLoaded)
959 for (i = 0;
960 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
961 i++)
962 LoadStringW(hInstance, keyUsageByte0Map[i].id,
963 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
964 for (i = 0;
965 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
966 i++)
967 LoadStringW(hInstance, keyUsageByte1Map[i].id,
968 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
969 stringsLoaded = TRUE;
971 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
972 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
973 NULL, &bitStringLen, &first);
974 bytesNeeded += bitStringLen;
975 if (bits->cbData == 2)
977 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
978 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
979 NULL, &bitStringLen, &first);
980 bytesNeeded += bitStringLen;
982 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
983 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
984 bits->cbData, NULL, &size);
985 bytesNeeded += size;
986 if (!pbFormat)
987 *pcbFormat = bytesNeeded;
988 else if (*pcbFormat < bytesNeeded)
990 *pcbFormat = bytesNeeded;
991 SetLastError(ERROR_MORE_DATA);
992 ret = FALSE;
994 else
996 LPWSTR str = pbFormat;
998 bitStringLen = bytesNeeded;
999 first = TRUE;
1000 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
1001 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
1002 str, &bitStringLen, &first);
1003 str += bitStringLen / sizeof(WCHAR) - 1;
1004 if (bits->cbData == 2)
1006 bitStringLen = bytesNeeded;
1007 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
1008 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
1009 str, &bitStringLen, &first);
1010 str += bitStringLen / sizeof(WCHAR) - 1;
1012 *str++ = ' ';
1013 *str++ = '(';
1014 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1015 bits->cbData, str, &size);
1016 str += size / sizeof(WCHAR) - 1;
1017 *str++ = ')';
1018 *str = 0;
1021 LocalFree(bits);
1023 return ret;
1026 static const WCHAR crlf[] = { '\r','\n',0 };
1028 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1029 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1030 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1031 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1033 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1034 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1035 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1036 DWORD *pcbFormat)
1038 DWORD size;
1039 CERT_BASIC_CONSTRAINTS2_INFO *info;
1040 BOOL ret;
1042 if (!cbEncoded)
1044 SetLastError(E_INVALIDARG);
1045 return FALSE;
1047 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1048 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1050 static const WCHAR pathFmt[] = { '%','d',0 };
1051 static BOOL stringsLoaded = FALSE;
1052 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1053 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1054 LPCWSTR sep, subjectType;
1055 DWORD sepLen;
1057 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1059 sep = crlf;
1060 sepLen = strlenW(crlf) * sizeof(WCHAR);
1062 else
1064 sep = commaSpace;
1065 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1068 if (!stringsLoaded)
1070 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
1071 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
1072 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
1073 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
1074 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
1075 subjectTypeEndCert,
1076 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
1077 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
1078 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
1079 stringsLoaded = TRUE;
1081 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
1082 if (info->fCA)
1083 subjectType = subjectTypeCA;
1084 else
1085 subjectType = subjectTypeEndCert;
1086 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
1087 bytesNeeded += sepLen;
1088 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
1089 if (info->fPathLenConstraint)
1090 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
1091 else
1092 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
1093 sizeof(pathLength) / sizeof(pathLength[0]));
1094 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
1095 if (!pbFormat)
1096 *pcbFormat = bytesNeeded;
1097 else if (*pcbFormat < bytesNeeded)
1099 *pcbFormat = bytesNeeded;
1100 SetLastError(ERROR_MORE_DATA);
1101 ret = FALSE;
1103 else
1105 LPWSTR str = pbFormat;
1107 *pcbFormat = bytesNeeded;
1108 strcpyW(str, subjectTypeHeader);
1109 str += strlenW(subjectTypeHeader);
1110 strcpyW(str, subjectType);
1111 str += strlenW(subjectType);
1112 strcpyW(str, sep);
1113 str += sepLen / sizeof(WCHAR);
1114 strcpyW(str, pathLengthHeader);
1115 str += strlenW(pathLengthHeader);
1116 strcpyW(str, pathLength);
1118 LocalFree(info);
1120 return ret;
1123 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1124 LPWSTR str, DWORD *pcbStr)
1126 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1127 DWORD bytesNeeded;
1128 BOOL ret;
1130 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1131 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1132 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1133 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1134 if (!str)
1136 *pcbStr = bytesNeeded;
1137 ret = TRUE;
1139 else if (*pcbStr < bytesNeeded)
1141 *pcbStr = bytesNeeded;
1142 SetLastError(ERROR_MORE_DATA);
1143 ret = FALSE;
1145 else
1147 *pcbStr = bytesNeeded;
1148 strcpyW(str, buf);
1149 str += strlenW(str);
1150 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1151 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1152 blob->pbData, blob->cbData, str, &bytesNeeded);
1154 return ret;
1157 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1158 DWORD *pcbStr)
1160 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1163 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1164 DWORD *pcbStr)
1166 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1167 str, pcbStr);
1170 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
1171 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
1173 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1174 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1176 BOOL ret;
1177 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1178 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1179 WCHAR ipAddrBuf[32];
1180 WCHAR maskBuf[16];
1181 DWORD bytesNeeded = sizeof(WCHAR);
1182 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1184 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1185 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1186 switch (entry->dwAltNameChoice)
1188 case CERT_ALT_NAME_RFC822_NAME:
1189 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
1190 sizeof(buf) / sizeof(buf[0]));
1191 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
1192 ret = TRUE;
1193 break;
1194 case CERT_ALT_NAME_DNS_NAME:
1195 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
1196 sizeof(buf) / sizeof(buf[0]));
1197 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
1198 ret = TRUE;
1199 break;
1200 case CERT_ALT_NAME_DIRECTORY_NAME:
1202 DWORD directoryNameLen;
1204 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1205 strType |= CERT_NAME_STR_CRLF_FLAG;
1206 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1207 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
1208 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
1209 sizeof(buf) / sizeof(buf[0]));
1210 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1211 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1212 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
1213 else
1214 bytesNeeded += sizeof(WCHAR); /* '=' */
1215 ret = TRUE;
1216 break;
1218 case CERT_ALT_NAME_URL:
1219 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
1220 sizeof(buf) / sizeof(buf[0]));
1221 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
1222 ret = TRUE;
1223 break;
1224 case CERT_ALT_NAME_IP_ADDRESS:
1226 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1227 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1229 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1230 '.','%','d',0 };
1232 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1233 sizeof(buf) / sizeof(buf[0]));
1234 if (entry->u.IPAddress.cbData == 8)
1236 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1238 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1239 sizeof(mask) / sizeof(mask[0]));
1240 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1241 sprintfW(ipAddrBuf, ipAddrFmt,
1242 entry->u.IPAddress.pbData[0],
1243 entry->u.IPAddress.pbData[1],
1244 entry->u.IPAddress.pbData[2],
1245 entry->u.IPAddress.pbData[3]);
1246 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1247 /* indent again, for the mask line */
1248 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1249 sprintfW(maskBuf, ipAddrFmt,
1250 entry->u.IPAddress.pbData[4],
1251 entry->u.IPAddress.pbData[5],
1252 entry->u.IPAddress.pbData[6],
1253 entry->u.IPAddress.pbData[7]);
1254 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1255 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1257 else
1259 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1260 entry->u.IPAddress.pbData[0],
1261 entry->u.IPAddress.pbData[1],
1262 entry->u.IPAddress.pbData[2],
1263 entry->u.IPAddress.pbData[3],
1264 entry->u.IPAddress.pbData[4],
1265 entry->u.IPAddress.pbData[5],
1266 entry->u.IPAddress.pbData[6],
1267 entry->u.IPAddress.pbData[7]);
1268 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1270 ret = TRUE;
1272 else
1274 FIXME("unknown IP address format (%d bytes)\n",
1275 entry->u.IPAddress.cbData);
1276 ret = FALSE;
1278 break;
1280 default:
1281 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1282 ret = FALSE;
1284 if (ret)
1286 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1287 if (!str)
1288 *pcbStr = bytesNeeded;
1289 else if (*pcbStr < bytesNeeded)
1291 *pcbStr = bytesNeeded;
1292 SetLastError(ERROR_MORE_DATA);
1293 ret = FALSE;
1295 else
1297 DWORD i;
1299 *pcbStr = bytesNeeded;
1300 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1302 for (i = 0; i < indentLevel; i++)
1304 strcpyW(str, indent);
1305 str += strlenW(indent);
1308 strcpyW(str, buf);
1309 str += strlenW(str);
1310 switch (entry->dwAltNameChoice)
1312 case CERT_ALT_NAME_RFC822_NAME:
1313 case CERT_ALT_NAME_DNS_NAME:
1314 case CERT_ALT_NAME_URL:
1315 strcpyW(str, entry->u.pwszURL);
1316 break;
1317 case CERT_ALT_NAME_DIRECTORY_NAME:
1318 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1320 strcpyW(str, colonCrlf);
1321 str += strlenW(colonCrlf);
1323 else
1324 *str++ = '=';
1325 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1326 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1327 bytesNeeded / sizeof(WCHAR));
1328 break;
1329 case CERT_ALT_NAME_IP_ADDRESS:
1330 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1332 strcpyW(str, ipAddrBuf);
1333 str += strlenW(ipAddrBuf);
1334 strcpyW(str, crlf);
1335 str += strlenW(crlf);
1336 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1338 for (i = 0; i < indentLevel; i++)
1340 strcpyW(str, indent);
1341 str += strlenW(indent);
1344 strcpyW(str, mask);
1345 str += strlenW(mask);
1346 strcpyW(str, maskBuf);
1348 else
1349 strcpyW(str, ipAddrBuf);
1350 break;
1354 return ret;
1357 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1358 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1360 DWORD i, size, bytesNeeded = 0;
1361 BOOL ret = TRUE;
1362 LPCWSTR sep;
1363 DWORD sepLen;
1365 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1367 sep = crlf;
1368 sepLen = strlenW(crlf) * sizeof(WCHAR);
1370 else
1372 sep = commaSpace;
1373 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1376 for (i = 0; ret && i < name->cAltEntry; i++)
1378 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1379 &name->rgAltEntry[i], NULL, &size);
1380 if (ret)
1382 bytesNeeded += size - sizeof(WCHAR);
1383 if (i < name->cAltEntry - 1)
1384 bytesNeeded += sepLen;
1387 if (ret)
1389 bytesNeeded += sizeof(WCHAR);
1390 if (!str)
1391 *pcbStr = bytesNeeded;
1392 else if (*pcbStr < bytesNeeded)
1394 *pcbStr = bytesNeeded;
1395 SetLastError(ERROR_MORE_DATA);
1396 ret = FALSE;
1398 else
1400 *pcbStr = bytesNeeded;
1401 for (i = 0; ret && i < name->cAltEntry; i++)
1403 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1404 &name->rgAltEntry[i], str, &size);
1405 if (ret)
1407 str += size / sizeof(WCHAR) - 1;
1408 if (i < name->cAltEntry - 1)
1410 strcpyW(str, sep);
1411 str += sepLen / sizeof(WCHAR);
1417 return ret;
1420 static const WCHAR colonSep[] = { ':',' ',0 };
1422 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1423 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1424 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1425 DWORD *pcbFormat)
1427 BOOL ret;
1428 CERT_ALT_NAME_INFO *info;
1429 DWORD size;
1431 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1432 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1434 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1435 LocalFree(info);
1437 return ret;
1440 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1441 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1443 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1444 DWORD bytesNeeded, sepLen;
1445 LPCWSTR sep;
1446 BOOL ret;
1448 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1449 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1450 &bytesNeeded);
1451 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1452 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1454 sep = colonCrlf;
1455 sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1457 else
1459 sep = colonSep;
1460 sepLen = strlenW(colonSep) * sizeof(WCHAR);
1462 bytesNeeded += sepLen;
1463 if (ret)
1465 if (!str)
1466 *pcbStr = bytesNeeded;
1467 else if (*pcbStr < bytesNeeded)
1469 *pcbStr = bytesNeeded;
1470 SetLastError(ERROR_MORE_DATA);
1471 ret = FALSE;
1473 else
1475 *pcbStr = bytesNeeded;
1476 strcpyW(str, buf);
1477 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1478 str += strlenW(str);
1479 strcpyW(str, sep);
1480 str += sepLen / sizeof(WCHAR);
1481 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1482 &bytesNeeded);
1485 return ret;
1488 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1489 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1490 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1491 DWORD *pcbFormat)
1493 CERT_AUTHORITY_KEY_ID2_INFO *info;
1494 DWORD size;
1495 BOOL ret = FALSE;
1497 if (!cbEncoded)
1499 SetLastError(E_INVALIDARG);
1500 return FALSE;
1502 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1503 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1505 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1506 LPCWSTR sep;
1507 DWORD sepLen;
1508 BOOL needSeparator = FALSE;
1510 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1512 sep = crlf;
1513 sepLen = strlenW(crlf) * sizeof(WCHAR);
1515 else
1517 sep = commaSpace;
1518 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1521 if (info->KeyId.cbData)
1523 needSeparator = TRUE;
1524 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1525 if (ret)
1527 /* don't include NULL-terminator more than once */
1528 bytesNeeded += size - sizeof(WCHAR);
1531 if (info->AuthorityCertIssuer.cAltEntry)
1533 if (needSeparator)
1534 bytesNeeded += sepLen;
1535 needSeparator = TRUE;
1536 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1537 &info->AuthorityCertIssuer, NULL, &size);
1538 if (ret)
1540 /* don't include NULL-terminator more than once */
1541 bytesNeeded += size - sizeof(WCHAR);
1544 if (info->AuthorityCertSerialNumber.cbData)
1546 if (needSeparator)
1547 bytesNeeded += sepLen;
1548 ret = CRYPT_FormatCertSerialNumber(
1549 &info->AuthorityCertSerialNumber, NULL, &size);
1550 if (ret)
1552 /* don't include NULL-terminator more than once */
1553 bytesNeeded += size - sizeof(WCHAR);
1556 if (ret)
1558 if (!pbFormat)
1559 *pcbFormat = bytesNeeded;
1560 else if (*pcbFormat < bytesNeeded)
1562 *pcbFormat = bytesNeeded;
1563 SetLastError(ERROR_MORE_DATA);
1564 ret = FALSE;
1566 else
1568 LPWSTR str = pbFormat;
1570 *pcbFormat = bytesNeeded;
1571 needSeparator = FALSE;
1572 if (info->KeyId.cbData)
1574 needSeparator = TRUE;
1575 /* Overestimate size available, it's already been checked
1576 * above.
1578 size = bytesNeeded;
1579 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1580 if (ret)
1581 str += size / sizeof(WCHAR) - 1;
1583 if (info->AuthorityCertIssuer.cAltEntry)
1585 if (needSeparator)
1587 strcpyW(str, sep);
1588 str += sepLen / sizeof(WCHAR);
1590 needSeparator = TRUE;
1591 /* Overestimate size available, it's already been checked
1592 * above.
1594 size = bytesNeeded;
1595 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1596 &info->AuthorityCertIssuer, str, &size);
1597 if (ret)
1598 str += size / sizeof(WCHAR) - 1;
1600 if (info->AuthorityCertSerialNumber.cbData)
1602 if (needSeparator)
1604 strcpyW(str, sep);
1605 str += sepLen / sizeof(WCHAR);
1607 /* Overestimate size available, it's already been checked
1608 * above.
1610 size = bytesNeeded;
1611 ret = CRYPT_FormatCertSerialNumber(
1612 &info->AuthorityCertSerialNumber, str, &size);
1616 LocalFree(info);
1618 return ret;
1621 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1622 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1623 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1624 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1625 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1626 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1628 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1629 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1630 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1631 DWORD *pcbFormat)
1633 CERT_AUTHORITY_INFO_ACCESS *info;
1634 DWORD size;
1635 BOOL ret = FALSE;
1637 if (!cbEncoded)
1639 SetLastError(E_INVALIDARG);
1640 return FALSE;
1642 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1643 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1644 NULL, &info, &size)))
1646 DWORD bytesNeeded = sizeof(WCHAR);
1648 if (!info->cAccDescr)
1650 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1652 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1653 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1654 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1655 if (!pbFormat)
1656 *pcbFormat = bytesNeeded;
1657 else if (*pcbFormat < bytesNeeded)
1659 *pcbFormat = bytesNeeded;
1660 SetLastError(ERROR_MORE_DATA);
1661 ret = FALSE;
1663 else
1665 *pcbFormat = bytesNeeded;
1666 strcpyW(pbFormat, infoNotAvailable);
1669 else
1671 static const WCHAR numFmt[] = { '%','d',0 };
1672 static const WCHAR equal[] = { '=',0 };
1673 static BOOL stringsLoaded = FALSE;
1674 DWORD i;
1675 LPCWSTR headingSep, accessMethodSep, locationSep;
1676 WCHAR accessDescrNum[11];
1678 if (!stringsLoaded)
1680 LoadStringW(hInstance, IDS_AIA, aia,
1681 sizeof(aia) / sizeof(aia[0]));
1682 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1683 sizeof(accessMethod) / sizeof(accessMethod[0]));
1684 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1685 sizeof(ocsp) / sizeof(ocsp[0]));
1686 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1687 sizeof(caIssuers) / sizeof(caIssuers[0]));
1688 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1689 sizeof(unknown) / sizeof(unknown[0]));
1690 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1691 sizeof(accessLocation) / sizeof(accessLocation[0]));
1692 stringsLoaded = TRUE;
1694 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1696 headingSep = crlf;
1697 accessMethodSep = crlf;
1698 locationSep = colonCrlf;
1700 else
1702 headingSep = colonSep;
1703 accessMethodSep = commaSpace;
1704 locationSep = equal;
1707 for (i = 0; ret && i < info->cAccDescr; i++)
1709 /* Heading */
1710 bytesNeeded += sizeof(WCHAR); /* left bracket */
1711 sprintfW(accessDescrNum, numFmt, i + 1);
1712 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1713 bytesNeeded += sizeof(WCHAR); /* right bracket */
1714 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1715 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1716 /* Access method */
1717 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1718 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1719 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1720 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1721 szOID_PKIX_OCSP))
1722 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1723 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1724 szOID_PKIX_CA_ISSUERS))
1725 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1726 else
1727 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1728 bytesNeeded += sizeof(WCHAR); /* space */
1729 bytesNeeded += sizeof(WCHAR); /* left paren */
1730 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1731 * sizeof(WCHAR);
1732 bytesNeeded += sizeof(WCHAR); /* right paren */
1733 /* Delimiter between access method and location */
1734 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1735 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1736 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1737 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1738 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1739 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1740 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1741 if (ret)
1742 bytesNeeded += size - sizeof(WCHAR);
1743 /* Need extra delimiter between access method entries */
1744 if (i < info->cAccDescr - 1)
1745 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1747 if (ret)
1749 if (!pbFormat)
1750 *pcbFormat = bytesNeeded;
1751 else if (*pcbFormat < bytesNeeded)
1753 *pcbFormat = bytesNeeded;
1754 SetLastError(ERROR_MORE_DATA);
1755 ret = FALSE;
1757 else
1759 LPWSTR str = pbFormat;
1760 DWORD altNameEntrySize;
1762 *pcbFormat = bytesNeeded;
1763 for (i = 0; ret && i < info->cAccDescr; i++)
1765 LPCSTR oidPtr;
1767 *str++ = '[';
1768 sprintfW(accessDescrNum, numFmt, i + 1);
1769 strcpyW(str, accessDescrNum);
1770 str += strlenW(accessDescrNum);
1771 *str++ = ']';
1772 strcpyW(str, aia);
1773 str += strlenW(aia);
1774 strcpyW(str, headingSep);
1775 str += strlenW(headingSep);
1776 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1778 strcpyW(str, indent);
1779 str += strlenW(indent);
1781 strcpyW(str, accessMethod);
1782 str += strlenW(accessMethod);
1783 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1784 szOID_PKIX_OCSP))
1786 strcpyW(str, ocsp);
1787 str += strlenW(ocsp);
1789 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1790 szOID_PKIX_CA_ISSUERS))
1792 strcpyW(str, caIssuers);
1793 str += strlenW(caIssuers);
1795 else
1797 strcpyW(str, unknown);
1798 str += strlenW(unknown);
1800 *str++ = ' ';
1801 *str++ = '(';
1802 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1803 *oidPtr; oidPtr++, str++)
1804 *str = *oidPtr;
1805 *str++ = ')';
1806 strcpyW(str, accessMethodSep);
1807 str += strlenW(accessMethodSep);
1808 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1810 strcpyW(str, indent);
1811 str += strlenW(indent);
1813 strcpyW(str, accessLocation);
1814 str += strlenW(accessLocation);
1815 strcpyW(str, locationSep);
1816 str += strlenW(locationSep);
1817 /* This overestimates the size available, but that
1818 * won't matter since we checked earlier whether enough
1819 * space for the entire string was available.
1821 altNameEntrySize = bytesNeeded;
1822 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1823 &info->rgAccDescr[i].AccessLocation, str,
1824 &altNameEntrySize);
1825 if (ret)
1826 str += altNameEntrySize / sizeof(WCHAR) - 1;
1827 if (i < info->cAccDescr - 1)
1829 strcpyW(str, accessMethodSep);
1830 str += strlenW(accessMethodSep);
1836 LocalFree(info);
1838 return ret;
1841 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1842 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1843 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1844 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1845 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1846 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1848 struct reason_map_entry
1850 BYTE reasonBit;
1851 LPWSTR reason;
1852 int id;
1854 static struct reason_map_entry reason_map[] = {
1855 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1856 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1857 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1858 IDS_REASON_AFFILIATION_CHANGED },
1859 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1860 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1861 IDS_REASON_CESSATION_OF_OPERATION },
1862 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1863 IDS_REASON_CERTIFICATE_HOLD },
1866 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1867 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1869 static const WCHAR sep[] = { ',',' ',0 };
1870 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1871 static BOOL stringsLoaded = FALSE;
1872 unsigned int i, numReasons = 0;
1873 BOOL ret = TRUE;
1874 DWORD bytesNeeded = sizeof(WCHAR);
1875 WCHAR bits[6];
1877 if (!stringsLoaded)
1879 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1880 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1881 MAX_STRING_RESOURCE_LEN);
1882 stringsLoaded = TRUE;
1884 /* No need to check reasonFlags->cbData, we already know it's positive.
1885 * Ignore any other bytes, as they're for undefined bits.
1887 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1889 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1891 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1892 if (numReasons++)
1893 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1896 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1897 bytesNeeded += strlenW(bits);
1898 if (!str)
1899 *pcbStr = bytesNeeded;
1900 else if (*pcbStr < bytesNeeded)
1902 *pcbStr = bytesNeeded;
1903 SetLastError(ERROR_MORE_DATA);
1904 ret = FALSE;
1906 else
1908 *pcbStr = bytesNeeded;
1909 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1911 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1913 strcpyW(str, reason_map[i].reason);
1914 str += strlenW(reason_map[i].reason);
1915 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1916 numReasons)
1918 strcpyW(str, sep);
1919 str += strlenW(sep);
1923 strcpyW(str, bits);
1925 return ret;
1928 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1929 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1930 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1931 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1932 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1933 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1935 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1936 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1937 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1938 DWORD *pcbFormat)
1940 CRL_DIST_POINTS_INFO *info;
1941 DWORD size;
1942 BOOL ret = FALSE;
1944 if (!cbEncoded)
1946 SetLastError(E_INVALIDARG);
1947 return FALSE;
1949 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1950 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1952 static const WCHAR numFmt[] = { '%','d',0 };
1953 static const WCHAR colon[] = { ':',0 };
1954 static BOOL stringsLoaded = FALSE;
1955 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1956 BOOL haveAnEntry = FALSE;
1957 LPCWSTR headingSep, nameSep;
1958 WCHAR distPointNum[11];
1959 DWORD i;
1961 if (!stringsLoaded)
1963 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1964 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1965 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1966 sizeof(distPointName) / sizeof(distPointName[0]));
1967 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1968 sizeof(fullName) / sizeof(fullName[0]));
1969 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1970 sizeof(rdnName) / sizeof(rdnName[0]));
1971 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1972 sizeof(reason) / sizeof(reason[0]));
1973 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1974 sizeof(issuer) / sizeof(issuer[0]));
1975 stringsLoaded = TRUE;
1977 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1979 headingSep = crlf;
1980 nameSep = colonCrlf;
1982 else
1984 headingSep = colonSep;
1985 nameSep = colon;
1988 for (i = 0; ret && i < info->cDistPoint; i++)
1990 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1992 if (distPoint->DistPointName.dwDistPointNameChoice !=
1993 CRL_DIST_POINT_NO_NAME)
1995 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1996 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1997 if (distPoint->DistPointName.dwDistPointNameChoice ==
1998 CRL_DIST_POINT_FULL_NAME)
1999 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
2000 else
2001 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
2002 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2003 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2004 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
2005 /* The indent level (3) is higher than when used as the issuer,
2006 * because the name is subordinate to the name type (full vs.
2007 * RDN.)
2009 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2010 &distPoint->DistPointName.u.FullName, NULL, &size);
2011 if (ret)
2012 bytesNeeded += size - sizeof(WCHAR);
2013 haveAnEntry = TRUE;
2015 else if (distPoint->ReasonFlags.cbData)
2017 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
2018 ret = CRYPT_FormatReason(dwFormatStrType,
2019 &distPoint->ReasonFlags, NULL, &size);
2020 if (ret)
2021 bytesNeeded += size - sizeof(WCHAR);
2022 haveAnEntry = TRUE;
2024 else if (distPoint->CRLIssuer.cAltEntry)
2026 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
2027 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2028 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2029 &distPoint->CRLIssuer, NULL, &size);
2030 if (ret)
2031 bytesNeeded += size - sizeof(WCHAR);
2032 haveAnEntry = TRUE;
2034 if (haveAnEntry)
2036 bytesNeeded += sizeof(WCHAR); /* left bracket */
2037 sprintfW(distPointNum, numFmt, i + 1);
2038 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
2039 bytesNeeded += sizeof(WCHAR); /* right bracket */
2040 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
2041 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
2042 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2043 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
2046 if (!haveAnEntry)
2048 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2050 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2051 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2052 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2053 if (!pbFormat)
2054 *pcbFormat = bytesNeeded;
2055 else if (*pcbFormat < bytesNeeded)
2057 *pcbFormat = bytesNeeded;
2058 SetLastError(ERROR_MORE_DATA);
2059 ret = FALSE;
2061 else
2063 *pcbFormat = bytesNeeded;
2064 strcpyW(pbFormat, infoNotAvailable);
2067 else
2069 if (!pbFormat)
2070 *pcbFormat = bytesNeeded;
2071 else if (*pcbFormat < bytesNeeded)
2073 *pcbFormat = bytesNeeded;
2074 SetLastError(ERROR_MORE_DATA);
2075 ret = FALSE;
2077 else
2079 LPWSTR str = pbFormat;
2081 *pcbFormat = bytesNeeded;
2082 for (i = 0; ret && i < info->cDistPoint; i++)
2084 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2086 *str++ = '[';
2087 sprintfW(distPointNum, numFmt, i + 1);
2088 strcpyW(str, distPointNum);
2089 str += strlenW(distPointNum);
2090 *str++ = ']';
2091 strcpyW(str, crlDistPoint);
2092 str += strlenW(crlDistPoint);
2093 strcpyW(str, headingSep);
2094 str += strlenW(headingSep);
2095 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2097 strcpyW(str, indent);
2098 str += strlenW(indent);
2100 if (distPoint->DistPointName.dwDistPointNameChoice !=
2101 CRL_DIST_POINT_NO_NAME)
2103 DWORD altNameSize = bytesNeeded;
2105 strcpyW(str, distPointName);
2106 str += strlenW(distPointName);
2107 strcpyW(str, nameSep);
2108 str += strlenW(nameSep);
2109 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2111 strcpyW(str, indent);
2112 str += strlenW(indent);
2113 strcpyW(str, indent);
2114 str += strlenW(indent);
2116 if (distPoint->DistPointName.dwDistPointNameChoice ==
2117 CRL_DIST_POINT_FULL_NAME)
2119 strcpyW(str, fullName);
2120 str += strlenW(fullName);
2122 else
2124 strcpyW(str, rdnName);
2125 str += strlenW(rdnName);
2127 strcpyW(str, nameSep);
2128 str += strlenW(nameSep);
2129 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2130 &distPoint->DistPointName.u.FullName, str,
2131 &altNameSize);
2132 if (ret)
2133 str += altNameSize / sizeof(WCHAR) - 1;
2135 else if (distPoint->ReasonFlags.cbData)
2137 DWORD reasonSize = bytesNeeded;
2139 strcpyW(str, reason);
2140 str += strlenW(reason);
2141 ret = CRYPT_FormatReason(dwFormatStrType,
2142 &distPoint->ReasonFlags, str, &reasonSize);
2143 if (ret)
2144 str += reasonSize / sizeof(WCHAR) - 1;
2146 else if (distPoint->CRLIssuer.cAltEntry)
2148 DWORD crlIssuerSize = bytesNeeded;
2150 strcpyW(str, issuer);
2151 str += strlenW(issuer);
2152 strcpyW(str, nameSep);
2153 str += strlenW(nameSep);
2154 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2155 &distPoint->CRLIssuer, str,
2156 &crlIssuerSize);
2157 if (ret)
2158 str += crlIssuerSize / sizeof(WCHAR) - 1;
2163 LocalFree(info);
2165 return ret;
2168 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2169 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2170 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2171 DWORD *pcbFormat)
2173 CERT_ENHKEY_USAGE *usage;
2174 DWORD size;
2175 BOOL ret = FALSE;
2177 if (!cbEncoded)
2179 SetLastError(E_INVALIDARG);
2180 return FALSE;
2182 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2183 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2185 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2186 DWORD i;
2187 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2188 LPCWSTR sep;
2189 DWORD sepLen;
2191 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2193 sep = crlf;
2194 sepLen = strlenW(crlf) * sizeof(WCHAR);
2196 else
2198 sep = commaSpace;
2199 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2202 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
2203 sizeof(unknown) / sizeof(unknown[0]));
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 += strlenW(info->pwszName) * sizeof(WCHAR);
2211 else
2212 bytesNeeded += strlenW(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 strcpyW(str, info->pwszName);
2244 str += strlenW(info->pwszName);
2246 else
2248 strcpyW(str, unknown);
2249 str += strlenW(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 strcpyW(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,
2300 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2301 if (!bits->cbData || bits->cbData > 1)
2303 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2304 if (!pbFormat)
2305 *pcbFormat = bytesNeeded;
2306 else if (*pcbFormat < bytesNeeded)
2308 *pcbFormat = bytesNeeded;
2309 SetLastError(ERROR_MORE_DATA);
2310 ret = FALSE;
2312 else
2314 LPWSTR str = pbFormat;
2316 *pcbFormat = bytesNeeded;
2317 strcpyW(str, infoNotAvailable);
2320 else
2322 static BOOL stringsLoaded = FALSE;
2323 unsigned int i;
2324 DWORD bitStringLen;
2325 BOOL first = TRUE;
2327 if (!stringsLoaded)
2329 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2330 sizeof(netscapeCertTypeMap[0]); i++)
2331 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2332 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2333 stringsLoaded = TRUE;
2335 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2336 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2337 NULL, &bitStringLen, &first);
2338 bytesNeeded += bitStringLen;
2339 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2340 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2341 bits->cbData, NULL, &size);
2342 bytesNeeded += size;
2343 if (!pbFormat)
2344 *pcbFormat = bytesNeeded;
2345 else if (*pcbFormat < bytesNeeded)
2347 *pcbFormat = bytesNeeded;
2348 SetLastError(ERROR_MORE_DATA);
2349 ret = FALSE;
2351 else
2353 LPWSTR str = pbFormat;
2355 bitStringLen = bytesNeeded;
2356 first = TRUE;
2357 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2358 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2359 str, &bitStringLen, &first);
2360 str += bitStringLen / sizeof(WCHAR) - 1;
2361 *str++ = ' ';
2362 *str++ = '(';
2363 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2364 bits->cbData, str, &size);
2365 str += size / sizeof(WCHAR) - 1;
2366 *str++ = ')';
2367 *str = 0;
2370 LocalFree(bits);
2372 return ret;
2375 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2376 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2377 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2378 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2379 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2380 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2382 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2383 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2384 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2385 DWORD *pcbFormat)
2387 SPC_FINANCIAL_CRITERIA criteria;
2388 DWORD size = sizeof(criteria);
2389 BOOL ret = FALSE;
2391 if (!cbEncoded)
2393 SetLastError(E_INVALIDARG);
2394 return FALSE;
2396 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2397 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2398 &size)))
2400 static BOOL stringsLoaded = FALSE;
2401 DWORD bytesNeeded = sizeof(WCHAR);
2402 LPCWSTR sep;
2403 DWORD sepLen;
2405 if (!stringsLoaded)
2407 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2408 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2409 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2410 sizeof(available) / sizeof(available[0]));
2411 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2412 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2413 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2414 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2415 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2416 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2417 stringsLoaded = TRUE;
2419 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2421 sep = crlf;
2422 sepLen = strlenW(crlf) * sizeof(WCHAR);
2424 else
2426 sep = commaSpace;
2427 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2429 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2430 if (criteria.fFinancialInfoAvailable)
2432 bytesNeeded += strlenW(available) * sizeof(WCHAR);
2433 bytesNeeded += sepLen;
2434 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2435 if (criteria.fMeetsCriteria)
2436 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2437 else
2438 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2440 else
2441 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2442 if (!pbFormat)
2443 *pcbFormat = bytesNeeded;
2444 else if (*pcbFormat < bytesNeeded)
2446 *pcbFormat = bytesNeeded;
2447 SetLastError(ERROR_MORE_DATA);
2448 ret = FALSE;
2450 else
2452 LPWSTR str = pbFormat;
2454 *pcbFormat = bytesNeeded;
2455 strcpyW(str, financialCriteria);
2456 str += strlenW(financialCriteria);
2457 if (criteria.fFinancialInfoAvailable)
2459 strcpyW(str, available);
2460 str += strlenW(available);
2461 strcpyW(str, sep);
2462 str += sepLen / sizeof(WCHAR);
2463 strcpyW(str, meetsCriteria);
2464 str += strlenW(meetsCriteria);
2465 if (criteria.fMeetsCriteria)
2466 strcpyW(str, yes);
2467 else
2468 strcpyW(str, no);
2470 else
2472 strcpyW(str, notAvailable);
2476 return ret;
2479 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2480 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2481 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2482 DWORD *pcbFormat)
2484 CERT_NAME_VALUE *value;
2485 DWORD size;
2486 BOOL ret;
2488 if (!cbEncoded)
2490 SetLastError(E_INVALIDARG);
2491 return FALSE;
2493 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2494 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2496 if (!pbFormat)
2497 *pcbFormat = value->Value.cbData;
2498 else if (*pcbFormat < value->Value.cbData)
2500 *pcbFormat = value->Value.cbData;
2501 SetLastError(ERROR_MORE_DATA);
2502 ret = FALSE;
2504 else
2506 LPWSTR str = pbFormat;
2508 *pcbFormat = value->Value.cbData;
2509 strcpyW(str, (LPWSTR)value->Value.pbData);
2512 return ret;
2515 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2516 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2518 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2519 DWORD formatStrType, LPCSTR lpszStructType)
2521 CryptFormatObjectFunc format = NULL;
2523 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2525 SetLastError(ERROR_FILE_NOT_FOUND);
2526 return NULL;
2528 if (IS_INTOID(lpszStructType))
2530 switch (LOWORD(lpszStructType))
2532 case LOWORD(X509_KEY_USAGE):
2533 format = CRYPT_FormatKeyUsage;
2534 break;
2535 case LOWORD(X509_ALTERNATE_NAME):
2536 format = CRYPT_FormatAltName;
2537 break;
2538 case LOWORD(X509_BASIC_CONSTRAINTS2):
2539 format = CRYPT_FormatBasicConstraints2;
2540 break;
2541 case LOWORD(X509_AUTHORITY_KEY_ID2):
2542 format = CRYPT_FormatAuthorityKeyId2;
2543 break;
2544 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2545 format = CRYPT_FormatAuthorityInfoAccess;
2546 break;
2547 case LOWORD(X509_CRL_DIST_POINTS):
2548 format = CRYPT_FormatCRLDistPoints;
2549 break;
2550 case LOWORD(X509_ENHANCED_KEY_USAGE):
2551 format = CRYPT_FormatEnhancedKeyUsage;
2552 break;
2553 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2554 format = CRYPT_FormatSpcFinancialCriteria;
2555 break;
2558 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2559 format = CRYPT_FormatAltName;
2560 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2561 format = CRYPT_FormatAltName;
2562 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2563 format = CRYPT_FormatKeyUsage;
2564 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2565 format = CRYPT_FormatAltName;
2566 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2567 format = CRYPT_FormatAltName;
2568 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2569 format = CRYPT_FormatBasicConstraints2;
2570 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2571 format = CRYPT_FormatAuthorityInfoAccess;
2572 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2573 format = CRYPT_FormatAuthorityKeyId2;
2574 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2575 format = CRYPT_FormatCRLDistPoints;
2576 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2577 format = CRYPT_FormatEnhancedKeyUsage;
2578 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2579 format = CRYPT_FormatNetscapeCertType;
2580 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2581 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2582 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2583 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2584 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2585 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2586 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2587 format = CRYPT_FormatUnicodeString;
2588 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2589 format = CRYPT_FormatSpcFinancialCriteria;
2590 return format;
2593 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2594 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2595 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2597 CryptFormatObjectFunc format = NULL;
2598 HCRYPTOIDFUNCADDR hFunc = NULL;
2599 BOOL ret = FALSE;
2601 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2602 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2603 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2605 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2606 dwFormatStrType, lpszStructType)))
2608 static HCRYPTOIDFUNCSET set = NULL;
2610 if (!set)
2611 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2612 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2613 (void **)&format, &hFunc);
2615 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2616 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2617 format = CRYPT_FormatHexString;
2618 if (format)
2619 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2620 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2621 pcbFormat);
2622 if (hFunc)
2623 CryptFreeOIDFunctionAddress(hFunc, 0);
2624 return ret;