msi: Free memory on error (valgrind).
[wine.git] / dlls / crypt32 / object.c
blob378ce51ee478a602ed077b413a25f691554cd7d8
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)
274 *ppvContext = contextInterface->duplicate(context);
277 end:
278 if (contextInterface && context)
279 contextInterface->free(context);
280 if (blob == &fileBlob)
281 CryptMemFree(blob->pbData);
282 TRACE("returning %d\n", ret);
283 return ret;
286 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
287 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
288 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
290 HANDLE file;
291 BOOL ret = FALSE;
293 TRACE("%s\n", debugstr_w(fileName));
294 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
295 OPEN_EXISTING, 0, NULL);
296 if (file != INVALID_HANDLE_VALUE)
298 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
299 CERT_STORE_CREATE_NEW_FLAG, NULL);
301 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
302 if (ret)
304 if (pdwMsgAndCertEncodingType)
305 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
306 if (pdwContentType)
307 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
308 if (phCertStore)
309 *phCertStore = CertDuplicateStore(store);
311 CertCloseStore(store, 0);
312 CloseHandle(file);
314 TRACE("returning %d\n", ret);
315 return ret;
318 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
319 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
320 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
322 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
323 CERT_STORE_CREATE_NEW_FLAG, NULL);
324 BOOL ret;
326 TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
328 ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
329 if (ret)
331 if (pdwMsgAndCertEncodingType)
332 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
333 if (pdwContentType)
334 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
335 if (phCertStore)
336 *phCertStore = CertDuplicateStore(store);
338 CertCloseStore(store, 0);
339 TRACE("returning %d\n", ret);
340 return ret;
343 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
344 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
345 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
347 switch (dwObjectType)
349 case CERT_QUERY_OBJECT_FILE:
350 return CRYPT_QuerySerializedStoreFromFile(pvObject,
351 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
352 case CERT_QUERY_OBJECT_BLOB:
353 return CRYPT_QuerySerializedStoreFromBlob(pvObject,
354 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
355 default:
356 FIXME("unimplemented for type %d\n", dwObjectType);
357 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
358 return FALSE;
362 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
363 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
365 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
366 BOOL ret = FALSE;
367 HCRYPTMSG msg;
369 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
371 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
372 if (ret)
374 DWORD type, len = sizeof(type);
376 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
377 if (ret)
379 if (type != CMSG_SIGNED)
381 SetLastError(ERROR_INVALID_DATA);
382 ret = FALSE;
386 if (!ret)
388 CryptMsgClose(msg);
389 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
390 NULL);
391 if (msg)
393 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
394 if (!ret)
396 CryptMsgClose(msg);
397 msg = NULL;
402 if (ret)
404 if (pdwMsgAndCertEncodingType)
405 *pdwMsgAndCertEncodingType = encodingType;
406 if (pdwContentType)
407 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
408 if (phMsg)
409 *phMsg = msg;
411 return ret;
414 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
415 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
417 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
418 BOOL ret = FALSE;
419 HCRYPTMSG msg;
421 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
423 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
424 if (ret)
426 DWORD type, len = sizeof(type);
428 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
429 if (ret)
431 if (type != CMSG_DATA)
433 SetLastError(ERROR_INVALID_DATA);
434 ret = FALSE;
438 if (!ret)
440 CryptMsgClose(msg);
441 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
442 NULL, NULL);
443 if (msg)
445 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
446 if (!ret)
448 CryptMsgClose(msg);
449 msg = NULL;
454 if (ret)
456 if (pdwMsgAndCertEncodingType)
457 *pdwMsgAndCertEncodingType = encodingType;
458 if (pdwContentType)
459 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
460 if (phMsg)
461 *phMsg = msg;
463 return ret;
466 /* Used to decode non-embedded messages */
467 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
468 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
469 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
470 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
472 CERT_BLOB fileBlob;
473 const CERT_BLOB *blob;
474 BOOL ret;
475 HCRYPTMSG msg = NULL;
476 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
477 DWORD formatType = 0;
479 TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
480 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
481 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
482 phMsg);
484 switch (dwObjectType)
486 case CERT_QUERY_OBJECT_FILE:
487 /* This isn't an embedded PKCS7 message, so just read the file
488 * directly
490 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
491 blob = &fileBlob;
492 break;
493 case CERT_QUERY_OBJECT_BLOB:
494 blob = pvObject;
495 ret = TRUE;
496 break;
497 default:
498 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
499 ret = FALSE;
501 if (!ret)
502 return FALSE;
504 ret = FALSE;
505 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
507 /* Try it first as a signed message */
508 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
509 ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
510 pdwContentType, &msg);
511 /* Failing that, try as an unsigned message */
512 if (!ret &&
513 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
514 ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
515 pdwContentType, &msg);
516 if (ret)
517 formatType = CERT_QUERY_FORMAT_BINARY;
519 if (!ret &&
520 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
522 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
523 CRYPT_DATA_BLOB decoded;
525 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
526 trimmed.cbData--;
527 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
528 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
529 if (ret)
531 decoded.pbData = CryptMemAlloc(decoded.cbData);
532 if (decoded.pbData)
534 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
535 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
536 &decoded.cbData, NULL, NULL);
537 if (ret)
539 /* Try it first as a signed message */
540 if (dwExpectedContentTypeFlags &
541 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
542 ret = CRYPT_QuerySignedMessage(&decoded,
543 pdwMsgAndCertEncodingType, pdwContentType, &msg);
544 /* Failing that, try as an unsigned message */
545 if (!ret && (dwExpectedContentTypeFlags &
546 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
547 ret = CRYPT_QueryUnsignedMessage(&decoded,
548 pdwMsgAndCertEncodingType, pdwContentType, &msg);
549 if (ret)
550 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
552 CryptMemFree(decoded.pbData);
554 else
555 ret = FALSE;
557 if (!ret && !(blob->cbData % sizeof(WCHAR)))
559 CRYPT_DATA_BLOB decoded;
560 LPWSTR str = (LPWSTR)blob->pbData;
561 DWORD strLen = blob->cbData / sizeof(WCHAR);
563 /* Try again, assuming the input string is UTF-16 base64 */
564 while (strLen && !str[strLen - 1])
565 strLen--;
566 ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
567 NULL, &decoded.cbData, NULL, NULL);
568 if (ret)
570 decoded.pbData = CryptMemAlloc(decoded.cbData);
571 if (decoded.pbData)
573 ret = CryptStringToBinaryW(str, strLen,
574 CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
575 NULL, NULL);
576 if (ret)
578 /* Try it first as a signed message */
579 if (dwExpectedContentTypeFlags &
580 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
581 ret = CRYPT_QuerySignedMessage(&decoded,
582 pdwMsgAndCertEncodingType, pdwContentType, &msg);
583 /* Failing that, try as an unsigned message */
584 if (!ret && (dwExpectedContentTypeFlags &
585 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
586 ret = CRYPT_QueryUnsignedMessage(&decoded,
587 pdwMsgAndCertEncodingType, pdwContentType, &msg);
588 if (ret)
589 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
591 CryptMemFree(decoded.pbData);
593 else
594 ret = FALSE;
598 if (ret)
600 if (pdwFormatType)
601 *pdwFormatType = formatType;
602 if (phCertStore)
603 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
604 0, msg);
605 if (phMsg)
606 *phMsg = msg;
607 else
608 CryptMsgClose(msg);
610 if (blob == &fileBlob)
611 CryptMemFree(blob->pbData);
612 TRACE("returning %d\n", ret);
613 return ret;
616 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
617 const void *pvObject, DWORD dwExpectedContentTypeFlags,
618 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
619 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
621 HANDLE file;
622 GUID subject;
623 BOOL ret = FALSE;
625 TRACE("%s\n", debugstr_w(pvObject));
627 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
629 WARN("don't know what to do for type %d embedded signed messages\n",
630 dwObjectType);
631 SetLastError(E_INVALIDARG);
632 return FALSE;
634 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
635 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
636 if (file != INVALID_HANDLE_VALUE)
638 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
639 if (ret)
641 SIP_DISPATCH_INFO sip;
643 memset(&sip, 0, sizeof(sip));
644 sip.cbSize = sizeof(sip);
645 ret = CryptSIPLoad(&subject, 0, &sip);
646 if (ret)
648 SIP_SUBJECTINFO subjectInfo;
649 CERT_BLOB blob;
650 DWORD encodingType;
652 memset(&subjectInfo, 0, sizeof(subjectInfo));
653 subjectInfo.cbSize = sizeof(subjectInfo);
654 subjectInfo.pgSubjectType = &subject;
655 subjectInfo.hFile = file;
656 subjectInfo.pwsFileName = pvObject;
657 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
658 NULL);
659 if (ret)
661 blob.pbData = CryptMemAlloc(blob.cbData);
662 if (blob.pbData)
664 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
665 &blob.cbData, blob.pbData);
666 if (ret)
668 ret = CRYPT_QueryMessageObject(
669 CERT_QUERY_OBJECT_BLOB, &blob,
670 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
671 CERT_QUERY_FORMAT_FLAG_BINARY,
672 pdwMsgAndCertEncodingType, NULL, NULL,
673 phCertStore, phMsg);
674 if (ret && pdwContentType)
675 *pdwContentType =
676 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
678 CryptMemFree(blob.pbData);
680 else
682 SetLastError(ERROR_OUTOFMEMORY);
683 ret = FALSE;
688 CloseHandle(file);
690 TRACE("returning %d\n", ret);
691 return ret;
694 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
695 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
696 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
697 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
698 const void **ppvContext)
700 static const DWORD unimplementedTypes =
701 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
702 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
703 BOOL ret = TRUE;
705 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
706 dwObjectType, pvObject, dwExpectedContentTypeFlags,
707 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
708 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
710 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
711 dwObjectType != CERT_QUERY_OBJECT_FILE)
713 WARN("unsupported type %d\n", dwObjectType);
714 SetLastError(E_INVALIDARG);
715 return FALSE;
717 if (!pvObject)
719 WARN("missing required argument\n");
720 SetLastError(E_INVALIDARG);
721 return FALSE;
723 if (dwExpectedContentTypeFlags & unimplementedTypes)
724 WARN("unimplemented for types %08x\n",
725 dwExpectedContentTypeFlags & unimplementedTypes);
727 if (pdwFormatType)
728 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
729 if (phCertStore)
730 *phCertStore = NULL;
731 if (phMsg)
732 *phMsg = NULL;
733 if (ppvContext)
734 *ppvContext = NULL;
736 ret = FALSE;
737 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
738 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
739 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
741 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
742 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
743 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
744 ppvContext);
746 if (!ret &&
747 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
749 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
750 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
752 if (!ret &&
753 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
754 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
755 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
757 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
758 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
759 phCertStore, ppvContext);
761 if (!ret &&
762 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
763 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
765 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
766 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
767 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
768 phCertStore, phMsg);
770 if (!ret &&
771 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
773 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
774 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
775 phCertStore, phMsg);
777 if (!ret)
778 SetLastError(CRYPT_E_NO_MATCH);
779 TRACE("returning %d\n", ret);
780 return ret;
783 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
784 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
785 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
786 DWORD *pcbFormat)
788 BOOL ret;
789 DWORD bytesNeeded;
791 if (cbEncoded)
792 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
793 else
794 bytesNeeded = sizeof(WCHAR);
795 if (!pbFormat)
797 *pcbFormat = bytesNeeded;
798 ret = TRUE;
800 else if (*pcbFormat < bytesNeeded)
802 *pcbFormat = bytesNeeded;
803 SetLastError(ERROR_MORE_DATA);
804 ret = FALSE;
806 else
808 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
809 static const WCHAR endFmt[] = { '%','0','2','x',0 };
810 DWORD i;
811 LPWSTR ptr = pbFormat;
813 *pcbFormat = bytesNeeded;
814 if (cbEncoded)
816 for (i = 0; i < cbEncoded; i++)
818 if (i < cbEncoded - 1)
819 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
820 else
821 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
824 else
825 *ptr = 0;
826 ret = TRUE;
828 return ret;
831 #define MAX_STRING_RESOURCE_LEN 128
833 static const WCHAR commaSpace[] = { ',',' ',0 };
835 struct BitToString
837 BYTE bit;
838 int id;
839 WCHAR str[MAX_STRING_RESOURCE_LEN];
842 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
843 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
845 DWORD bytesNeeded = sizeof(WCHAR);
846 int i;
847 BOOL ret = TRUE, localFirst = *first;
849 for (i = 0; i < mapEntries; i++)
850 if (bits & map[i].bit)
852 if (!localFirst)
853 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
854 localFirst = FALSE;
855 bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
857 if (!pbFormat)
859 *first = localFirst;
860 *pcbFormat = bytesNeeded;
862 else if (*pcbFormat < bytesNeeded)
864 *first = localFirst;
865 *pcbFormat = bytesNeeded;
866 SetLastError(ERROR_MORE_DATA);
867 ret = FALSE;
869 else
871 LPWSTR str = pbFormat;
873 localFirst = *first;
874 *pcbFormat = bytesNeeded;
875 for (i = 0; i < mapEntries; i++)
876 if (bits & map[i].bit)
878 if (!localFirst)
880 strcpyW(str, commaSpace);
881 str += strlenW(commaSpace);
883 localFirst = FALSE;
884 strcpyW(str, map[i].str);
885 str += strlenW(map[i].str);
887 *first = localFirst;
889 return ret;
892 static struct BitToString keyUsageByte0Map[] = {
893 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
894 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
895 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
896 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
897 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
898 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
899 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
900 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
901 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
903 static struct BitToString keyUsageByte1Map[] = {
904 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
907 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
908 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
909 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
910 DWORD *pcbFormat)
912 DWORD size;
913 CRYPT_BIT_BLOB *bits;
914 BOOL ret;
916 if (!cbEncoded)
918 SetLastError(E_INVALIDARG);
919 return FALSE;
921 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
922 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
924 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
925 DWORD bytesNeeded = sizeof(WCHAR);
927 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
928 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
929 if (!bits->cbData || bits->cbData > 2)
931 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
932 if (!pbFormat)
933 *pcbFormat = bytesNeeded;
934 else if (*pcbFormat < bytesNeeded)
936 *pcbFormat = bytesNeeded;
937 SetLastError(ERROR_MORE_DATA);
938 ret = FALSE;
940 else
942 LPWSTR str = pbFormat;
944 *pcbFormat = bytesNeeded;
945 strcpyW(str, infoNotAvailable);
948 else
950 static BOOL stringsLoaded = FALSE;
951 int i;
952 DWORD bitStringLen;
953 BOOL first = TRUE;
955 if (!stringsLoaded)
957 for (i = 0;
958 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
959 i++)
960 LoadStringW(hInstance, keyUsageByte0Map[i].id,
961 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
962 for (i = 0;
963 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
964 i++)
965 LoadStringW(hInstance, keyUsageByte1Map[i].id,
966 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
967 stringsLoaded = TRUE;
969 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
970 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
971 NULL, &bitStringLen, &first);
972 bytesNeeded += bitStringLen;
973 if (bits->cbData == 2)
975 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
976 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
977 NULL, &bitStringLen, &first);
978 bytesNeeded += bitStringLen;
980 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
981 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
982 bits->cbData, NULL, &size);
983 bytesNeeded += size;
984 if (!pbFormat)
985 *pcbFormat = bytesNeeded;
986 else if (*pcbFormat < bytesNeeded)
988 *pcbFormat = bytesNeeded;
989 SetLastError(ERROR_MORE_DATA);
990 ret = FALSE;
992 else
994 LPWSTR str = pbFormat;
996 bitStringLen = bytesNeeded;
997 first = TRUE;
998 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
999 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
1000 str, &bitStringLen, &first);
1001 str += bitStringLen / sizeof(WCHAR) - 1;
1002 if (bits->cbData == 2)
1004 bitStringLen = bytesNeeded;
1005 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
1006 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
1007 str, &bitStringLen, &first);
1008 str += bitStringLen / sizeof(WCHAR) - 1;
1010 *str++ = ' ';
1011 *str++ = '(';
1012 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1013 bits->cbData, str, &size);
1014 str += size / sizeof(WCHAR) - 1;
1015 *str++ = ')';
1016 *str = 0;
1019 LocalFree(bits);
1021 return ret;
1024 static const WCHAR crlf[] = { '\r','\n',0 };
1026 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1027 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1028 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1029 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1031 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1032 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1033 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1034 DWORD *pcbFormat)
1036 DWORD size;
1037 CERT_BASIC_CONSTRAINTS2_INFO *info;
1038 BOOL ret;
1040 if (!cbEncoded)
1042 SetLastError(E_INVALIDARG);
1043 return FALSE;
1045 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1046 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1048 static const WCHAR pathFmt[] = { '%','d',0 };
1049 static BOOL stringsLoaded = FALSE;
1050 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1051 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1052 LPCWSTR sep, subjectType;
1053 DWORD sepLen;
1055 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1057 sep = crlf;
1058 sepLen = strlenW(crlf) * sizeof(WCHAR);
1060 else
1062 sep = commaSpace;
1063 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1066 if (!stringsLoaded)
1068 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
1069 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
1070 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
1071 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
1072 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
1073 subjectTypeEndCert,
1074 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
1075 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
1076 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
1077 stringsLoaded = TRUE;
1079 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
1080 if (info->fCA)
1081 subjectType = subjectTypeCA;
1082 else
1083 subjectType = subjectTypeEndCert;
1084 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
1085 bytesNeeded += sepLen;
1086 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
1087 if (info->fPathLenConstraint)
1088 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
1089 else
1090 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
1091 sizeof(pathLength) / sizeof(pathLength[0]));
1092 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
1093 if (!pbFormat)
1094 *pcbFormat = bytesNeeded;
1095 else if (*pcbFormat < bytesNeeded)
1097 *pcbFormat = bytesNeeded;
1098 SetLastError(ERROR_MORE_DATA);
1099 ret = FALSE;
1101 else
1103 LPWSTR str = pbFormat;
1105 *pcbFormat = bytesNeeded;
1106 strcpyW(str, subjectTypeHeader);
1107 str += strlenW(subjectTypeHeader);
1108 strcpyW(str, subjectType);
1109 str += strlenW(subjectType);
1110 strcpyW(str, sep);
1111 str += sepLen / sizeof(WCHAR);
1112 strcpyW(str, pathLengthHeader);
1113 str += strlenW(pathLengthHeader);
1114 strcpyW(str, pathLength);
1115 str += strlenW(pathLength);
1117 LocalFree(info);
1119 return ret;
1122 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1123 LPWSTR str, DWORD *pcbStr)
1125 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1126 DWORD bytesNeeded;
1127 BOOL ret;
1129 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1130 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1131 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1132 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1133 if (!str)
1135 *pcbStr = bytesNeeded;
1136 ret = TRUE;
1138 else if (*pcbStr < bytesNeeded)
1140 *pcbStr = bytesNeeded;
1141 SetLastError(ERROR_MORE_DATA);
1142 ret = FALSE;
1144 else
1146 *pcbStr = bytesNeeded;
1147 strcpyW(str, buf);
1148 str += strlenW(str);
1149 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1150 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1151 blob->pbData, blob->cbData, str, &bytesNeeded);
1153 return ret;
1156 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1157 DWORD *pcbStr)
1159 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1162 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1163 DWORD *pcbStr)
1165 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1166 str, pcbStr);
1169 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
1170 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
1172 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1173 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1175 BOOL ret;
1176 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1177 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1178 WCHAR ipAddrBuf[32];
1179 WCHAR maskBuf[16];
1180 DWORD bytesNeeded = sizeof(WCHAR);
1181 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1183 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1184 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1185 switch (entry->dwAltNameChoice)
1187 case CERT_ALT_NAME_RFC822_NAME:
1188 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
1189 sizeof(buf) / sizeof(buf[0]));
1190 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
1191 ret = TRUE;
1192 break;
1193 case CERT_ALT_NAME_DNS_NAME:
1194 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
1195 sizeof(buf) / sizeof(buf[0]));
1196 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
1197 ret = TRUE;
1198 break;
1199 case CERT_ALT_NAME_DIRECTORY_NAME:
1201 DWORD directoryNameLen;
1203 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1204 strType |= CERT_NAME_STR_CRLF_FLAG;
1205 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1206 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
1207 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
1208 sizeof(buf) / sizeof(buf[0]));
1209 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1210 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1211 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
1212 else
1213 bytesNeeded += sizeof(WCHAR); /* '=' */
1214 ret = TRUE;
1215 break;
1217 case CERT_ALT_NAME_URL:
1218 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
1219 sizeof(buf) / sizeof(buf[0]));
1220 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
1221 ret = TRUE;
1222 break;
1223 case CERT_ALT_NAME_IP_ADDRESS:
1225 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1226 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1228 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1229 '.','%','d',0 };
1231 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1232 sizeof(buf) / sizeof(buf[0]));
1233 if (entry->u.IPAddress.cbData == 8)
1235 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1237 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1238 sizeof(mask) / sizeof(mask[0]));
1239 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1240 sprintfW(ipAddrBuf, ipAddrFmt,
1241 entry->u.IPAddress.pbData[0],
1242 entry->u.IPAddress.pbData[1],
1243 entry->u.IPAddress.pbData[2],
1244 entry->u.IPAddress.pbData[3]);
1245 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1246 /* indent again, for the mask line */
1247 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1248 sprintfW(maskBuf, ipAddrFmt,
1249 entry->u.IPAddress.pbData[4],
1250 entry->u.IPAddress.pbData[5],
1251 entry->u.IPAddress.pbData[6],
1252 entry->u.IPAddress.pbData[7]);
1253 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1254 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1256 else
1258 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1259 entry->u.IPAddress.pbData[0],
1260 entry->u.IPAddress.pbData[1],
1261 entry->u.IPAddress.pbData[2],
1262 entry->u.IPAddress.pbData[3],
1263 entry->u.IPAddress.pbData[4],
1264 entry->u.IPAddress.pbData[5],
1265 entry->u.IPAddress.pbData[6],
1266 entry->u.IPAddress.pbData[7]);
1267 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1269 ret = TRUE;
1271 else
1273 FIXME("unknown IP address format (%d bytes)\n",
1274 entry->u.IPAddress.cbData);
1275 ret = FALSE;
1277 break;
1279 default:
1280 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1281 ret = FALSE;
1283 if (ret)
1285 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1286 if (!str)
1287 *pcbStr = bytesNeeded;
1288 else if (*pcbStr < bytesNeeded)
1290 *pcbStr = bytesNeeded;
1291 SetLastError(ERROR_MORE_DATA);
1292 ret = FALSE;
1294 else
1296 DWORD i;
1298 *pcbStr = bytesNeeded;
1299 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1301 for (i = 0; i < indentLevel; i++)
1303 strcpyW(str, indent);
1304 str += strlenW(indent);
1307 strcpyW(str, buf);
1308 str += strlenW(str);
1309 switch (entry->dwAltNameChoice)
1311 case CERT_ALT_NAME_RFC822_NAME:
1312 case CERT_ALT_NAME_DNS_NAME:
1313 case CERT_ALT_NAME_URL:
1314 strcpyW(str, entry->u.pwszURL);
1315 break;
1316 case CERT_ALT_NAME_DIRECTORY_NAME:
1317 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1319 strcpyW(str, colonCrlf);
1320 str += strlenW(colonCrlf);
1322 else
1323 *str++ = '=';
1324 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1325 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1326 bytesNeeded / sizeof(WCHAR));
1327 break;
1328 case CERT_ALT_NAME_IP_ADDRESS:
1329 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1331 strcpyW(str, ipAddrBuf);
1332 str += strlenW(ipAddrBuf);
1333 strcpyW(str, crlf);
1334 str += strlenW(crlf);
1335 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1337 for (i = 0; i < indentLevel; i++)
1339 strcpyW(str, indent);
1340 str += strlenW(indent);
1343 strcpyW(str, mask);
1344 str += strlenW(mask);
1345 strcpyW(str, maskBuf);
1347 else
1348 strcpyW(str, ipAddrBuf);
1349 break;
1353 return ret;
1356 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1357 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1359 DWORD i, size, bytesNeeded = 0;
1360 BOOL ret = TRUE;
1361 LPCWSTR sep;
1362 DWORD sepLen;
1364 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1366 sep = crlf;
1367 sepLen = strlenW(crlf) * sizeof(WCHAR);
1369 else
1371 sep = commaSpace;
1372 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1375 for (i = 0; ret && i < name->cAltEntry; i++)
1377 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1378 &name->rgAltEntry[i], NULL, &size);
1379 if (ret)
1381 bytesNeeded += size - sizeof(WCHAR);
1382 if (i < name->cAltEntry - 1)
1383 bytesNeeded += sepLen;
1386 if (ret)
1388 bytesNeeded += sizeof(WCHAR);
1389 if (!str)
1390 *pcbStr = bytesNeeded;
1391 else if (*pcbStr < bytesNeeded)
1393 *pcbStr = bytesNeeded;
1394 SetLastError(ERROR_MORE_DATA);
1395 ret = FALSE;
1397 else
1399 *pcbStr = bytesNeeded;
1400 for (i = 0; ret && i < name->cAltEntry; i++)
1402 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1403 &name->rgAltEntry[i], str, &size);
1404 if (ret)
1406 str += size / sizeof(WCHAR) - 1;
1407 if (i < name->cAltEntry - 1)
1409 strcpyW(str, sep);
1410 str += sepLen / sizeof(WCHAR);
1416 return ret;
1419 static const WCHAR colonSep[] = { ':',' ',0 };
1421 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1422 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1423 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1424 DWORD *pcbFormat)
1426 BOOL ret;
1427 CERT_ALT_NAME_INFO *info;
1428 DWORD size;
1430 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1431 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1433 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1434 LocalFree(info);
1436 return ret;
1439 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1440 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1442 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1443 DWORD bytesNeeded, sepLen;
1444 LPCWSTR sep;
1445 BOOL ret;
1447 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1448 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1449 &bytesNeeded);
1450 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1451 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1453 sep = colonCrlf;
1454 sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1456 else
1458 sep = colonSep;
1459 sepLen = strlenW(colonSep) * sizeof(WCHAR);
1461 bytesNeeded += sepLen;
1462 if (ret)
1464 if (!str)
1465 *pcbStr = bytesNeeded;
1466 else if (*pcbStr < bytesNeeded)
1468 *pcbStr = bytesNeeded;
1469 SetLastError(ERROR_MORE_DATA);
1470 ret = FALSE;
1472 else
1474 *pcbStr = bytesNeeded;
1475 strcpyW(str, buf);
1476 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1477 str += strlenW(str);
1478 strcpyW(str, sep);
1479 str += sepLen / sizeof(WCHAR);
1480 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1481 &bytesNeeded);
1484 return ret;
1487 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1488 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1489 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1490 DWORD *pcbFormat)
1492 CERT_AUTHORITY_KEY_ID2_INFO *info;
1493 DWORD size;
1494 BOOL ret = FALSE;
1496 if (!cbEncoded)
1498 SetLastError(E_INVALIDARG);
1499 return FALSE;
1501 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1502 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1504 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1505 LPCWSTR sep;
1506 DWORD sepLen;
1507 BOOL needSeparator = FALSE;
1509 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1511 sep = crlf;
1512 sepLen = strlenW(crlf) * sizeof(WCHAR);
1514 else
1516 sep = commaSpace;
1517 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1520 if (info->KeyId.cbData)
1522 needSeparator = TRUE;
1523 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1524 if (ret)
1526 /* don't include NULL-terminator more than once */
1527 bytesNeeded += size - sizeof(WCHAR);
1530 if (info->AuthorityCertIssuer.cAltEntry)
1532 if (needSeparator)
1533 bytesNeeded += sepLen;
1534 needSeparator = TRUE;
1535 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1536 &info->AuthorityCertIssuer, NULL, &size);
1537 if (ret)
1539 /* don't include NULL-terminator more than once */
1540 bytesNeeded += size - sizeof(WCHAR);
1543 if (info->AuthorityCertSerialNumber.cbData)
1545 if (needSeparator)
1546 bytesNeeded += sepLen;
1547 ret = CRYPT_FormatCertSerialNumber(
1548 &info->AuthorityCertSerialNumber, NULL, &size);
1549 if (ret)
1551 /* don't include NULL-terminator more than once */
1552 bytesNeeded += size - sizeof(WCHAR);
1555 if (ret)
1557 if (!pbFormat)
1558 *pcbFormat = bytesNeeded;
1559 else if (*pcbFormat < bytesNeeded)
1561 *pcbFormat = bytesNeeded;
1562 SetLastError(ERROR_MORE_DATA);
1563 ret = FALSE;
1565 else
1567 LPWSTR str = pbFormat;
1569 *pcbFormat = bytesNeeded;
1570 needSeparator = FALSE;
1571 if (info->KeyId.cbData)
1573 needSeparator = TRUE;
1574 /* Overestimate size available, it's already been checked
1575 * above.
1577 size = bytesNeeded;
1578 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1579 if (ret)
1580 str += size / sizeof(WCHAR) - 1;
1582 if (info->AuthorityCertIssuer.cAltEntry)
1584 if (needSeparator)
1586 strcpyW(str, sep);
1587 str += sepLen / sizeof(WCHAR);
1589 needSeparator = TRUE;
1590 /* Overestimate size available, it's already been checked
1591 * above.
1593 size = bytesNeeded;
1594 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1595 &info->AuthorityCertIssuer, str, &size);
1596 if (ret)
1597 str += size / sizeof(WCHAR) - 1;
1599 if (info->AuthorityCertSerialNumber.cbData)
1601 if (needSeparator)
1603 strcpyW(str, sep);
1604 str += sepLen / sizeof(WCHAR);
1606 /* Overestimate size available, it's already been checked
1607 * above.
1609 size = bytesNeeded;
1610 ret = CRYPT_FormatCertSerialNumber(
1611 &info->AuthorityCertSerialNumber, str, &size);
1615 LocalFree(info);
1617 return ret;
1620 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1621 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1622 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1623 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1624 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1625 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1627 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1628 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1629 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1630 DWORD *pcbFormat)
1632 CERT_AUTHORITY_INFO_ACCESS *info;
1633 DWORD size;
1634 BOOL ret = FALSE;
1636 if (!cbEncoded)
1638 SetLastError(E_INVALIDARG);
1639 return FALSE;
1641 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1642 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1643 NULL, &info, &size)))
1645 DWORD bytesNeeded = sizeof(WCHAR);
1647 if (!info->cAccDescr)
1649 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1651 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1652 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1653 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1654 if (!pbFormat)
1655 *pcbFormat = bytesNeeded;
1656 else if (*pcbFormat < bytesNeeded)
1658 *pcbFormat = bytesNeeded;
1659 SetLastError(ERROR_MORE_DATA);
1660 ret = FALSE;
1662 else
1664 *pcbFormat = bytesNeeded;
1665 strcpyW(pbFormat, infoNotAvailable);
1668 else
1670 static const WCHAR numFmt[] = { '%','d',0 };
1671 static const WCHAR equal[] = { '=',0 };
1672 static BOOL stringsLoaded = FALSE;
1673 DWORD i;
1674 LPCWSTR headingSep, accessMethodSep, locationSep;
1675 WCHAR accessDescrNum[11];
1677 if (!stringsLoaded)
1679 LoadStringW(hInstance, IDS_AIA, aia,
1680 sizeof(aia) / sizeof(aia[0]));
1681 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1682 sizeof(accessMethod) / sizeof(accessMethod[0]));
1683 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1684 sizeof(ocsp) / sizeof(ocsp[0]));
1685 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1686 sizeof(caIssuers) / sizeof(caIssuers[0]));
1687 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1688 sizeof(unknown) / sizeof(unknown[0]));
1689 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1690 sizeof(accessLocation) / sizeof(accessLocation[0]));
1691 stringsLoaded = TRUE;
1693 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1695 headingSep = crlf;
1696 accessMethodSep = crlf;
1697 locationSep = colonCrlf;
1699 else
1701 headingSep = colonSep;
1702 accessMethodSep = commaSpace;
1703 locationSep = equal;
1706 for (i = 0; ret && i < info->cAccDescr; i++)
1708 /* Heading */
1709 bytesNeeded += sizeof(WCHAR); /* left bracket */
1710 sprintfW(accessDescrNum, numFmt, i + 1);
1711 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1712 bytesNeeded += sizeof(WCHAR); /* right bracket */
1713 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1714 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1715 /* Access method */
1716 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1717 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1718 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1719 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1720 szOID_PKIX_OCSP))
1721 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1722 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1723 szOID_PKIX_CA_ISSUERS))
1724 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1725 else
1726 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1727 bytesNeeded += sizeof(WCHAR); /* space */
1728 bytesNeeded += sizeof(WCHAR); /* left paren */
1729 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1730 * sizeof(WCHAR);
1731 bytesNeeded += sizeof(WCHAR); /* right paren */
1732 /* Delimiter between access method and location */
1733 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1734 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1735 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1736 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1737 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1738 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1739 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1740 if (ret)
1741 bytesNeeded += size - sizeof(WCHAR);
1742 /* Need extra delimiter between access method entries */
1743 if (i < info->cAccDescr - 1)
1744 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1746 if (ret)
1748 if (!pbFormat)
1749 *pcbFormat = bytesNeeded;
1750 else if (*pcbFormat < bytesNeeded)
1752 *pcbFormat = bytesNeeded;
1753 SetLastError(ERROR_MORE_DATA);
1754 ret = FALSE;
1756 else
1758 LPWSTR str = pbFormat;
1759 DWORD altNameEntrySize;
1761 *pcbFormat = bytesNeeded;
1762 for (i = 0; ret && i < info->cAccDescr; i++)
1764 LPCSTR oidPtr;
1766 *str++ = '[';
1767 sprintfW(accessDescrNum, numFmt, i + 1);
1768 strcpyW(str, accessDescrNum);
1769 str += strlenW(accessDescrNum);
1770 *str++ = ']';
1771 strcpyW(str, aia);
1772 str += strlenW(aia);
1773 strcpyW(str, headingSep);
1774 str += strlenW(headingSep);
1775 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1777 strcpyW(str, indent);
1778 str += strlenW(indent);
1780 strcpyW(str, accessMethod);
1781 str += strlenW(accessMethod);
1782 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1783 szOID_PKIX_OCSP))
1785 strcpyW(str, ocsp);
1786 str += strlenW(ocsp);
1788 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1789 szOID_PKIX_CA_ISSUERS))
1791 strcpyW(str, caIssuers);
1792 str += strlenW(caIssuers);
1794 else
1796 strcpyW(str, unknown);
1797 str += strlenW(unknown);
1799 *str++ = ' ';
1800 *str++ = '(';
1801 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1802 *oidPtr; oidPtr++, str++)
1803 *str = *oidPtr;
1804 *str++ = ')';
1805 strcpyW(str, accessMethodSep);
1806 str += strlenW(accessMethodSep);
1807 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1809 strcpyW(str, indent);
1810 str += strlenW(indent);
1812 strcpyW(str, accessLocation);
1813 str += strlenW(accessLocation);
1814 strcpyW(str, locationSep);
1815 str += strlenW(locationSep);
1816 /* This overestimates the size available, but that
1817 * won't matter since we checked earlier whether enough
1818 * space for the entire string was available.
1820 altNameEntrySize = bytesNeeded;
1821 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1822 &info->rgAccDescr[i].AccessLocation, str,
1823 &altNameEntrySize);
1824 if (ret)
1825 str += altNameEntrySize / sizeof(WCHAR) - 1;
1826 if (i < info->cAccDescr - 1)
1828 strcpyW(str, accessMethodSep);
1829 str += strlenW(accessMethodSep);
1835 LocalFree(info);
1837 return ret;
1840 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1841 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1842 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1843 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1844 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1845 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1847 struct reason_map_entry
1849 BYTE reasonBit;
1850 LPWSTR reason;
1851 int id;
1853 static struct reason_map_entry reason_map[] = {
1854 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1855 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1856 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1857 IDS_REASON_AFFILIATION_CHANGED },
1858 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1859 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1860 IDS_REASON_CESSATION_OF_OPERATION },
1861 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1862 IDS_REASON_CERTIFICATE_HOLD },
1865 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1866 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1868 static const WCHAR sep[] = { ',',' ',0 };
1869 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1870 static BOOL stringsLoaded = FALSE;
1871 int i, numReasons = 0;
1872 BOOL ret = TRUE;
1873 DWORD bytesNeeded = sizeof(WCHAR);
1874 WCHAR bits[6];
1876 if (!stringsLoaded)
1878 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1879 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1880 MAX_STRING_RESOURCE_LEN);
1881 stringsLoaded = TRUE;
1883 /* No need to check reasonFlags->cbData, we already know it's positive.
1884 * Ignore any other bytes, as they're for undefined bits.
1886 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1888 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1890 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1891 if (numReasons++)
1892 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1895 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1896 bytesNeeded += strlenW(bits);
1897 if (!str)
1898 *pcbStr = bytesNeeded;
1899 else if (*pcbStr < bytesNeeded)
1901 *pcbStr = bytesNeeded;
1902 SetLastError(ERROR_MORE_DATA);
1903 ret = FALSE;
1905 else
1907 *pcbStr = bytesNeeded;
1908 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1910 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1912 strcpyW(str, reason_map[i].reason);
1913 str += strlenW(reason_map[i].reason);
1914 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1915 numReasons)
1917 strcpyW(str, sep);
1918 str += strlenW(sep);
1922 strcpyW(str, bits);
1924 return ret;
1927 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1928 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1929 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1930 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1931 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1932 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1934 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1935 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1936 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1937 DWORD *pcbFormat)
1939 CRL_DIST_POINTS_INFO *info;
1940 DWORD size;
1941 BOOL ret = FALSE;
1943 if (!cbEncoded)
1945 SetLastError(E_INVALIDARG);
1946 return FALSE;
1948 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1949 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1951 static const WCHAR numFmt[] = { '%','d',0 };
1952 static const WCHAR colon[] = { ':',0 };
1953 static BOOL stringsLoaded = FALSE;
1954 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1955 BOOL haveAnEntry = FALSE;
1956 LPCWSTR headingSep, nameSep;
1957 WCHAR distPointNum[11];
1958 DWORD i;
1960 if (!stringsLoaded)
1962 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1963 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1964 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1965 sizeof(distPointName) / sizeof(distPointName[0]));
1966 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1967 sizeof(fullName) / sizeof(fullName[0]));
1968 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1969 sizeof(rdnName) / sizeof(rdnName[0]));
1970 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1971 sizeof(reason) / sizeof(reason[0]));
1972 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1973 sizeof(issuer) / sizeof(issuer[0]));
1974 stringsLoaded = TRUE;
1976 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1978 headingSep = crlf;
1979 nameSep = colonCrlf;
1981 else
1983 headingSep = colonSep;
1984 nameSep = colon;
1987 for (i = 0; ret && i < info->cDistPoint; i++)
1989 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1991 if (distPoint->DistPointName.dwDistPointNameChoice !=
1992 CRL_DIST_POINT_NO_NAME)
1994 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1995 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1996 if (distPoint->DistPointName.dwDistPointNameChoice ==
1997 CRL_DIST_POINT_FULL_NAME)
1998 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
1999 else
2000 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
2001 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2002 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2003 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
2004 /* The indent level (3) is higher than when used as the issuer,
2005 * because the name is subordinate to the name type (full vs.
2006 * RDN.)
2008 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2009 &distPoint->DistPointName.u.FullName, NULL, &size);
2010 if (ret)
2011 bytesNeeded += size - sizeof(WCHAR);
2012 haveAnEntry = TRUE;
2014 else if (distPoint->ReasonFlags.cbData)
2016 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
2017 ret = CRYPT_FormatReason(dwFormatStrType,
2018 &distPoint->ReasonFlags, NULL, &size);
2019 if (ret)
2020 bytesNeeded += size - sizeof(WCHAR);
2021 haveAnEntry = TRUE;
2023 else if (distPoint->CRLIssuer.cAltEntry)
2025 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
2026 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2027 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2028 &distPoint->CRLIssuer, NULL, &size);
2029 if (ret)
2030 bytesNeeded += size - sizeof(WCHAR);
2031 haveAnEntry = TRUE;
2033 if (haveAnEntry)
2035 bytesNeeded += sizeof(WCHAR); /* left bracket */
2036 sprintfW(distPointNum, numFmt, i + 1);
2037 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
2038 bytesNeeded += sizeof(WCHAR); /* right bracket */
2039 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
2040 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
2041 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2042 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
2045 if (!haveAnEntry)
2047 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2049 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2050 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2051 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2052 if (!pbFormat)
2053 *pcbFormat = bytesNeeded;
2054 else if (*pcbFormat < bytesNeeded)
2056 *pcbFormat = bytesNeeded;
2057 SetLastError(ERROR_MORE_DATA);
2058 ret = FALSE;
2060 else
2062 *pcbFormat = bytesNeeded;
2063 strcpyW(pbFormat, infoNotAvailable);
2066 else
2068 if (!pbFormat)
2069 *pcbFormat = bytesNeeded;
2070 else if (*pcbFormat < bytesNeeded)
2072 *pcbFormat = bytesNeeded;
2073 SetLastError(ERROR_MORE_DATA);
2074 ret = FALSE;
2076 else
2078 LPWSTR str = pbFormat;
2080 *pcbFormat = bytesNeeded;
2081 for (i = 0; ret && i < info->cDistPoint; i++)
2083 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2085 *str++ = '[';
2086 sprintfW(distPointNum, numFmt, i + 1);
2087 strcpyW(str, distPointNum);
2088 str += strlenW(distPointNum);
2089 *str++ = ']';
2090 strcpyW(str, crlDistPoint);
2091 str += strlenW(crlDistPoint);
2092 strcpyW(str, headingSep);
2093 str += strlenW(headingSep);
2094 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2096 strcpyW(str, indent);
2097 str += strlenW(indent);
2099 if (distPoint->DistPointName.dwDistPointNameChoice !=
2100 CRL_DIST_POINT_NO_NAME)
2102 DWORD altNameSize = bytesNeeded;
2104 strcpyW(str, distPointName);
2105 str += strlenW(distPointName);
2106 strcpyW(str, nameSep);
2107 str += strlenW(nameSep);
2108 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2110 strcpyW(str, indent);
2111 str += strlenW(indent);
2112 strcpyW(str, indent);
2113 str += strlenW(indent);
2115 if (distPoint->DistPointName.dwDistPointNameChoice ==
2116 CRL_DIST_POINT_FULL_NAME)
2118 strcpyW(str, fullName);
2119 str += strlenW(fullName);
2121 else
2123 strcpyW(str, rdnName);
2124 str += strlenW(rdnName);
2126 strcpyW(str, nameSep);
2127 str += strlenW(nameSep);
2128 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2129 &distPoint->DistPointName.u.FullName, str,
2130 &altNameSize);
2131 if (ret)
2132 str += altNameSize / sizeof(WCHAR) - 1;
2134 else if (distPoint->ReasonFlags.cbData)
2136 DWORD reasonSize = bytesNeeded;
2138 strcpyW(str, reason);
2139 str += strlenW(reason);
2140 ret = CRYPT_FormatReason(dwFormatStrType,
2141 &distPoint->ReasonFlags, str, &reasonSize);
2142 if (ret)
2143 str += reasonSize / sizeof(WCHAR) - 1;
2145 else if (distPoint->CRLIssuer.cAltEntry)
2147 DWORD crlIssuerSize = bytesNeeded;
2149 strcpyW(str, issuer);
2150 str += strlenW(issuer);
2151 strcpyW(str, nameSep);
2152 str += strlenW(nameSep);
2153 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2154 &distPoint->CRLIssuer, str,
2155 &crlIssuerSize);
2156 if (ret)
2157 str += crlIssuerSize / sizeof(WCHAR) - 1;
2162 LocalFree(info);
2164 return ret;
2167 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2168 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2169 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2170 DWORD *pcbFormat)
2172 CERT_ENHKEY_USAGE *usage;
2173 DWORD size;
2174 BOOL ret = FALSE;
2176 if (!cbEncoded)
2178 SetLastError(E_INVALIDARG);
2179 return FALSE;
2181 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2182 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2184 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2185 DWORD i;
2186 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2187 LPCWSTR sep;
2188 DWORD sepLen;
2190 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2192 sep = crlf;
2193 sepLen = strlenW(crlf) * sizeof(WCHAR);
2195 else
2197 sep = commaSpace;
2198 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2201 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
2202 sizeof(unknown) / sizeof(unknown[0]));
2203 for (i = 0; i < usage->cUsageIdentifier; i++)
2205 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2206 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2208 if (info)
2209 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
2210 else
2211 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
2212 bytesNeeded += sizeof(WCHAR); /* space */
2213 bytesNeeded += sizeof(WCHAR); /* left paren */
2214 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
2215 sizeof(WCHAR);
2216 bytesNeeded += sizeof(WCHAR); /* right paren */
2217 if (i < usage->cUsageIdentifier - 1)
2218 bytesNeeded += sepLen;
2220 if (!pbFormat)
2221 *pcbFormat = bytesNeeded;
2222 else if (*pcbFormat < bytesNeeded)
2224 *pcbFormat = bytesNeeded;
2225 SetLastError(ERROR_MORE_DATA);
2226 ret = FALSE;
2228 else
2230 LPWSTR str = pbFormat;
2232 *pcbFormat = bytesNeeded;
2233 for (i = 0; i < usage->cUsageIdentifier; i++)
2235 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2236 usage->rgpszUsageIdentifier[i],
2237 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2238 LPCSTR oidPtr;
2240 if (info)
2242 strcpyW(str, info->pwszName);
2243 str += strlenW(info->pwszName);
2245 else
2247 strcpyW(str, unknown);
2248 str += strlenW(unknown);
2250 *str++ = ' ';
2251 *str++ = '(';
2252 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2253 *str++ = *oidPtr;
2254 *str++ = ')';
2255 *str = 0;
2256 if (i < usage->cUsageIdentifier - 1)
2258 strcpyW(str, sep);
2259 str += sepLen / sizeof(WCHAR);
2263 LocalFree(usage);
2265 return ret;
2268 static struct BitToString netscapeCertTypeMap[] = {
2269 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2270 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2271 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2272 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2273 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2274 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2275 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2278 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2279 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2280 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2281 DWORD *pcbFormat)
2283 DWORD size;
2284 CRYPT_BIT_BLOB *bits;
2285 BOOL ret;
2287 if (!cbEncoded)
2289 SetLastError(E_INVALIDARG);
2290 return FALSE;
2292 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2293 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2295 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2296 DWORD bytesNeeded = sizeof(WCHAR);
2298 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2299 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2300 if (!bits->cbData || bits->cbData > 1)
2302 bytesNeeded += strlenW(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 strcpyW(str, infoNotAvailable);
2319 else
2321 static BOOL stringsLoaded = FALSE;
2322 int i;
2323 DWORD bitStringLen;
2324 BOOL first = TRUE;
2326 if (!stringsLoaded)
2328 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2329 sizeof(netscapeCertTypeMap[0]); i++)
2330 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2331 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2332 stringsLoaded = TRUE;
2334 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2335 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2336 NULL, &bitStringLen, &first);
2337 bytesNeeded += bitStringLen;
2338 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2339 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2340 bits->cbData, NULL, &size);
2341 bytesNeeded += size;
2342 if (!pbFormat)
2343 *pcbFormat = bytesNeeded;
2344 else if (*pcbFormat < bytesNeeded)
2346 *pcbFormat = bytesNeeded;
2347 SetLastError(ERROR_MORE_DATA);
2348 ret = FALSE;
2350 else
2352 LPWSTR str = pbFormat;
2354 bitStringLen = bytesNeeded;
2355 first = TRUE;
2356 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2357 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2358 str, &bitStringLen, &first);
2359 str += bitStringLen / sizeof(WCHAR) - 1;
2360 *str++ = ' ';
2361 *str++ = '(';
2362 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2363 bits->cbData, str, &size);
2364 str += size / sizeof(WCHAR) - 1;
2365 *str++ = ')';
2366 *str = 0;
2369 LocalFree(bits);
2371 return ret;
2374 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2375 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2376 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2377 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2378 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2379 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2381 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2382 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2383 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2384 DWORD *pcbFormat)
2386 SPC_FINANCIAL_CRITERIA criteria;
2387 DWORD size = sizeof(criteria);
2388 BOOL ret = FALSE;
2390 if (!cbEncoded)
2392 SetLastError(E_INVALIDARG);
2393 return FALSE;
2395 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2396 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2397 &size)))
2399 static BOOL stringsLoaded = FALSE;
2400 DWORD bytesNeeded = sizeof(WCHAR);
2401 LPCWSTR sep;
2402 DWORD sepLen;
2404 if (!stringsLoaded)
2406 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2407 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2408 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2409 sizeof(available) / sizeof(available[0]));
2410 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2411 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2412 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2413 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2414 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2415 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2416 stringsLoaded = TRUE;
2418 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2420 sep = crlf;
2421 sepLen = strlenW(crlf) * sizeof(WCHAR);
2423 else
2425 sep = commaSpace;
2426 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2428 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2429 if (criteria.fFinancialInfoAvailable)
2431 bytesNeeded += strlenW(available) * sizeof(WCHAR);
2432 bytesNeeded += sepLen;
2433 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2434 if (criteria.fMeetsCriteria)
2435 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2436 else
2437 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2439 else
2440 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2441 if (!pbFormat)
2442 *pcbFormat = bytesNeeded;
2443 else if (*pcbFormat < bytesNeeded)
2445 *pcbFormat = bytesNeeded;
2446 SetLastError(ERROR_MORE_DATA);
2447 ret = FALSE;
2449 else
2451 LPWSTR str = pbFormat;
2453 *pcbFormat = bytesNeeded;
2454 strcpyW(str, financialCriteria);
2455 str += strlenW(financialCriteria);
2456 if (criteria.fFinancialInfoAvailable)
2458 strcpyW(str, available);
2459 str += strlenW(available);
2460 strcpyW(str, sep);
2461 str += sepLen / sizeof(WCHAR);
2462 strcpyW(str, meetsCriteria);
2463 str += strlenW(meetsCriteria);
2464 if (criteria.fMeetsCriteria)
2465 strcpyW(str, yes);
2466 else
2467 strcpyW(str, no);
2469 else
2471 strcpyW(str, notAvailable);
2472 str += strlenW(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;