version: Use the string value length when converting strings.
[wine.git] / dlls / crypt32 / object.c
blob0320cfda1bbaeaa3abb138e14f9ac2e7a6f2ed4e
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) && read == blob->cbData;
56 if (!ret) CryptMemFree(blob->pbData);
58 else
59 ret = FALSE;
61 CloseHandle(file);
63 TRACE("returning %d\n", ret);
64 return ret;
67 static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
68 DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
69 DWORD *contentType, const void **ppvContext)
71 BOOL ret = FALSE;
73 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
75 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
76 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
77 if (ret && contentType)
78 *contentType = CERT_QUERY_CONTENT_CERT;
80 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
82 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
83 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
84 if (ret && contentType)
85 *contentType = CERT_QUERY_CONTENT_CRL;
87 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
89 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
90 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
91 if (ret && contentType)
92 *contentType = CERT_QUERY_CONTENT_CTL;
94 return ret;
97 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
98 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
99 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
100 HCERTSTORE *phCertStore, const void **ppvContext)
102 CERT_BLOB fileBlob;
103 const CERT_BLOB *blob;
104 HCERTSTORE store;
105 BOOL ret;
106 DWORD formatType = 0;
108 switch (dwObjectType)
110 case CERT_QUERY_OBJECT_FILE:
111 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
112 * just read the file directly
114 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
115 blob = &fileBlob;
116 break;
117 case CERT_QUERY_OBJECT_BLOB:
118 blob = pvObject;
119 ret = TRUE;
120 break;
121 default:
122 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
123 ret = FALSE;
125 if (!ret)
126 return FALSE;
128 ret = FALSE;
129 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
130 CERT_STORE_CREATE_NEW_FLAG, NULL);
131 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
133 ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
134 pdwContentType, ppvContext);
135 if (ret)
136 formatType = CERT_QUERY_FORMAT_BINARY;
138 if (!ret &&
139 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
141 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
142 CRYPT_DATA_BLOB decoded;
144 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
145 trimmed.cbData--;
146 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
147 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
148 if (ret)
150 decoded.pbData = CryptMemAlloc(decoded.cbData);
151 if (decoded.pbData)
153 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
154 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
155 &decoded.cbData, NULL, NULL);
156 if (ret)
158 ret = CRYPT_QueryContextBlob(&decoded,
159 dwExpectedContentTypeFlags, store, pdwContentType,
160 ppvContext);
161 if (ret)
162 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
164 CryptMemFree(decoded.pbData);
166 else
167 ret = FALSE;
170 if (ret)
172 if (pdwMsgAndCertEncodingType)
173 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
174 if (pdwFormatType)
175 *pdwFormatType = formatType;
176 if (phCertStore)
177 *phCertStore = CertDuplicateStore(store);
179 CertCloseStore(store, 0);
180 if (blob == &fileBlob)
181 CryptMemFree(blob->pbData);
182 TRACE("returning %d\n", ret);
183 return ret;
186 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
187 const void *pvObject, DWORD dwExpectedContentTypeFlags,
188 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
189 HCERTSTORE *phCertStore, const void **ppvContext)
191 CERT_BLOB fileBlob;
192 const CERT_BLOB *blob;
193 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
194 const void *context;
195 DWORD contextType;
196 BOOL ret;
198 switch (dwObjectType)
200 case CERT_QUERY_OBJECT_FILE:
201 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
202 * just read the file directly
204 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
205 blob = &fileBlob;
206 break;
207 case CERT_QUERY_OBJECT_BLOB:
208 blob = pvObject;
209 ret = TRUE;
210 break;
211 default:
212 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
213 ret = FALSE;
215 if (!ret)
216 return FALSE;
218 ret = FALSE;
219 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
220 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
221 if (context)
223 DWORD contentType, certStoreOffset;
225 ret = TRUE;
226 switch (contextType)
228 case CERT_STORE_CERTIFICATE_CONTEXT:
229 contextInterface = pCertInterface;
230 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
231 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
232 if (!(dwExpectedContentTypeFlags &
233 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
235 SetLastError(ERROR_INVALID_DATA);
236 ret = FALSE;
237 goto end;
239 break;
240 case CERT_STORE_CRL_CONTEXT:
241 contextInterface = pCRLInterface;
242 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
243 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
244 if (!(dwExpectedContentTypeFlags &
245 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
247 SetLastError(ERROR_INVALID_DATA);
248 ret = FALSE;
249 goto end;
251 break;
252 case CERT_STORE_CTL_CONTEXT:
253 contextInterface = pCTLInterface;
254 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
255 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
256 if (!(dwExpectedContentTypeFlags &
257 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
259 SetLastError(ERROR_INVALID_DATA);
260 ret = FALSE;
261 goto end;
263 break;
264 default:
265 SetLastError(ERROR_INVALID_DATA);
266 ret = FALSE;
267 goto end;
269 if (pdwMsgAndCertEncodingType)
270 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
271 if (pdwContentType)
272 *pdwContentType = contentType;
273 if (phCertStore)
274 *phCertStore = CertDuplicateStore(
275 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
276 if (ppvContext)
278 *ppvContext = context;
279 Context_AddRef(context_from_ptr(context));
283 end:
284 if (contextInterface && context)
285 Context_Release(context_from_ptr(context));
286 if (blob == &fileBlob)
287 CryptMemFree(blob->pbData);
288 TRACE("returning %d\n", ret);
289 return ret;
292 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
293 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
294 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
296 HANDLE file;
297 BOOL ret = FALSE;
299 TRACE("%s\n", debugstr_w(fileName));
300 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
301 OPEN_EXISTING, 0, NULL);
302 if (file != INVALID_HANDLE_VALUE)
304 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
305 CERT_STORE_CREATE_NEW_FLAG, NULL);
307 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
308 if (ret)
310 if (pdwMsgAndCertEncodingType)
311 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
312 if (pdwContentType)
313 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
314 if (phCertStore)
315 *phCertStore = CertDuplicateStore(store);
317 CertCloseStore(store, 0);
318 CloseHandle(file);
320 TRACE("returning %d\n", ret);
321 return ret;
324 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
325 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
326 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
328 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
329 CERT_STORE_CREATE_NEW_FLAG, NULL);
330 BOOL ret;
332 TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
334 ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
335 if (ret)
337 if (pdwMsgAndCertEncodingType)
338 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
339 if (pdwContentType)
340 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
341 if (phCertStore)
342 *phCertStore = CertDuplicateStore(store);
344 CertCloseStore(store, 0);
345 TRACE("returning %d\n", ret);
346 return ret;
349 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
350 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
351 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
353 switch (dwObjectType)
355 case CERT_QUERY_OBJECT_FILE:
356 return CRYPT_QuerySerializedStoreFromFile(pvObject,
357 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
358 case CERT_QUERY_OBJECT_BLOB:
359 return CRYPT_QuerySerializedStoreFromBlob(pvObject,
360 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
361 default:
362 FIXME("unimplemented for type %d\n", dwObjectType);
363 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
364 return FALSE;
368 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
369 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
371 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
372 BOOL ret = FALSE;
373 HCRYPTMSG msg;
375 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
377 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
378 if (ret)
380 DWORD type, len = sizeof(type);
382 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
383 if (ret)
385 if (type != CMSG_SIGNED)
387 SetLastError(ERROR_INVALID_DATA);
388 ret = FALSE;
392 if (!ret)
394 CryptMsgClose(msg);
395 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
396 NULL);
397 if (msg)
399 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
400 if (!ret)
402 CryptMsgClose(msg);
403 msg = NULL;
408 if (ret)
410 if (pdwMsgAndCertEncodingType)
411 *pdwMsgAndCertEncodingType = encodingType;
412 if (pdwContentType)
413 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
414 if (phMsg)
415 *phMsg = msg;
417 return ret;
420 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
421 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
423 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
424 BOOL ret = FALSE;
425 HCRYPTMSG msg;
427 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
429 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
430 if (ret)
432 DWORD type, len = sizeof(type);
434 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
435 if (ret)
437 if (type != CMSG_DATA)
439 SetLastError(ERROR_INVALID_DATA);
440 ret = FALSE;
444 if (!ret)
446 CryptMsgClose(msg);
447 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
448 NULL, NULL);
449 if (msg)
451 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
452 if (!ret)
454 CryptMsgClose(msg);
455 msg = NULL;
460 if (ret)
462 if (pdwMsgAndCertEncodingType)
463 *pdwMsgAndCertEncodingType = encodingType;
464 if (pdwContentType)
465 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
466 if (phMsg)
467 *phMsg = msg;
469 return ret;
472 /* Used to decode non-embedded messages */
473 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
474 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
475 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
476 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
478 CERT_BLOB fileBlob;
479 const CERT_BLOB *blob;
480 BOOL ret;
481 HCRYPTMSG msg = NULL;
482 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
483 DWORD formatType = 0;
485 TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
486 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
487 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
488 phMsg);
490 switch (dwObjectType)
492 case CERT_QUERY_OBJECT_FILE:
493 /* This isn't an embedded PKCS7 message, so just read the file
494 * directly
496 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
497 blob = &fileBlob;
498 break;
499 case CERT_QUERY_OBJECT_BLOB:
500 blob = pvObject;
501 ret = TRUE;
502 break;
503 default:
504 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
505 ret = FALSE;
507 if (!ret)
508 return FALSE;
510 ret = FALSE;
511 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
513 /* Try it first as a signed message */
514 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
515 ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
516 pdwContentType, &msg);
517 /* Failing that, try as an unsigned message */
518 if (!ret &&
519 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
520 ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
521 pdwContentType, &msg);
522 if (ret)
523 formatType = CERT_QUERY_FORMAT_BINARY;
525 if (!ret &&
526 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
528 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
529 CRYPT_DATA_BLOB decoded;
531 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
532 trimmed.cbData--;
533 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
534 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
535 if (ret)
537 decoded.pbData = CryptMemAlloc(decoded.cbData);
538 if (decoded.pbData)
540 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
541 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
542 &decoded.cbData, NULL, NULL);
543 if (ret)
545 /* Try it first as a signed message */
546 if (dwExpectedContentTypeFlags &
547 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
548 ret = CRYPT_QuerySignedMessage(&decoded,
549 pdwMsgAndCertEncodingType, pdwContentType, &msg);
550 /* Failing that, try as an unsigned message */
551 if (!ret && (dwExpectedContentTypeFlags &
552 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
553 ret = CRYPT_QueryUnsignedMessage(&decoded,
554 pdwMsgAndCertEncodingType, pdwContentType, &msg);
555 if (ret)
556 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
558 CryptMemFree(decoded.pbData);
560 else
561 ret = FALSE;
563 if (!ret && !(blob->cbData % sizeof(WCHAR)))
565 CRYPT_DATA_BLOB decoded;
566 LPWSTR str = (LPWSTR)blob->pbData;
567 DWORD strLen = blob->cbData / sizeof(WCHAR);
569 /* Try again, assuming the input string is UTF-16 base64 */
570 while (strLen && !str[strLen - 1])
571 strLen--;
572 ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
573 NULL, &decoded.cbData, NULL, NULL);
574 if (ret)
576 decoded.pbData = CryptMemAlloc(decoded.cbData);
577 if (decoded.pbData)
579 ret = CryptStringToBinaryW(str, strLen,
580 CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
581 NULL, NULL);
582 if (ret)
584 /* Try it first as a signed message */
585 if (dwExpectedContentTypeFlags &
586 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
587 ret = CRYPT_QuerySignedMessage(&decoded,
588 pdwMsgAndCertEncodingType, pdwContentType, &msg);
589 /* Failing that, try as an unsigned message */
590 if (!ret && (dwExpectedContentTypeFlags &
591 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
592 ret = CRYPT_QueryUnsignedMessage(&decoded,
593 pdwMsgAndCertEncodingType, pdwContentType, &msg);
594 if (ret)
595 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
597 CryptMemFree(decoded.pbData);
599 else
600 ret = FALSE;
604 if (ret)
606 if (pdwFormatType)
607 *pdwFormatType = formatType;
608 if (phCertStore)
609 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
610 0, msg);
611 if (phMsg)
612 *phMsg = msg;
613 else
614 CryptMsgClose(msg);
616 if (blob == &fileBlob)
617 CryptMemFree(blob->pbData);
618 TRACE("returning %d\n", ret);
619 return ret;
622 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
623 const void *pvObject, DWORD dwExpectedContentTypeFlags,
624 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
625 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
627 HANDLE file;
628 GUID subject;
629 BOOL ret = FALSE;
631 TRACE("%s\n", debugstr_w(pvObject));
633 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
635 WARN("don't know what to do for type %d embedded signed messages\n",
636 dwObjectType);
637 SetLastError(E_INVALIDARG);
638 return FALSE;
640 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
641 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
642 if (file != INVALID_HANDLE_VALUE)
644 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
645 if (ret)
647 SIP_DISPATCH_INFO sip;
649 memset(&sip, 0, sizeof(sip));
650 sip.cbSize = sizeof(sip);
651 ret = CryptSIPLoad(&subject, 0, &sip);
652 if (ret)
654 SIP_SUBJECTINFO subjectInfo;
655 CERT_BLOB blob;
656 DWORD encodingType;
658 memset(&subjectInfo, 0, sizeof(subjectInfo));
659 subjectInfo.cbSize = sizeof(subjectInfo);
660 subjectInfo.pgSubjectType = &subject;
661 subjectInfo.hFile = file;
662 subjectInfo.pwsFileName = pvObject;
663 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
664 NULL);
665 if (ret)
667 blob.pbData = CryptMemAlloc(blob.cbData);
668 if (blob.pbData)
670 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
671 &blob.cbData, blob.pbData);
672 if (ret)
674 ret = CRYPT_QueryMessageObject(
675 CERT_QUERY_OBJECT_BLOB, &blob,
676 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
677 CERT_QUERY_FORMAT_FLAG_BINARY,
678 pdwMsgAndCertEncodingType, NULL, NULL,
679 phCertStore, phMsg);
680 if (ret && pdwContentType)
681 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
683 CryptMemFree(blob.pbData);
685 else
687 SetLastError(ERROR_OUTOFMEMORY);
688 ret = FALSE;
693 CloseHandle(file);
695 TRACE("returning %d\n", ret);
696 return ret;
699 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
700 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
701 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
702 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
703 const void **ppvContext)
705 static const DWORD unimplementedTypes =
706 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
707 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
708 BOOL ret = TRUE;
710 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
711 dwObjectType, pvObject, dwExpectedContentTypeFlags,
712 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
713 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
715 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
716 dwObjectType != CERT_QUERY_OBJECT_FILE)
718 WARN("unsupported type %d\n", dwObjectType);
719 SetLastError(E_INVALIDARG);
720 return FALSE;
722 if (!pvObject)
724 WARN("missing required argument\n");
725 SetLastError(E_INVALIDARG);
726 return FALSE;
728 if (dwExpectedContentTypeFlags & unimplementedTypes)
729 WARN("unimplemented for types %08x\n",
730 dwExpectedContentTypeFlags & unimplementedTypes);
732 if (pdwFormatType)
733 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
734 if (phCertStore)
735 *phCertStore = NULL;
736 if (phMsg)
737 *phMsg = NULL;
738 if (ppvContext)
739 *ppvContext = NULL;
741 ret = FALSE;
742 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
743 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
744 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
746 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
747 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
748 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
749 ppvContext);
751 if (!ret &&
752 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
754 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
755 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
757 if (!ret &&
758 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
759 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
760 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
762 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
763 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
764 phCertStore, ppvContext);
766 if (!ret &&
767 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
768 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
770 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
771 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
772 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
773 phCertStore, phMsg);
775 if (!ret &&
776 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
778 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
779 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
780 phCertStore, phMsg);
782 if (!ret)
783 SetLastError(CRYPT_E_NO_MATCH);
784 TRACE("returning %d\n", ret);
785 return ret;
788 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
789 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
790 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
791 DWORD *pcbFormat)
793 BOOL ret;
794 DWORD bytesNeeded;
796 if (cbEncoded)
797 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
798 else
799 bytesNeeded = sizeof(WCHAR);
800 if (!pbFormat)
802 *pcbFormat = bytesNeeded;
803 ret = TRUE;
805 else if (*pcbFormat < bytesNeeded)
807 *pcbFormat = bytesNeeded;
808 SetLastError(ERROR_MORE_DATA);
809 ret = FALSE;
811 else
813 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
814 static const WCHAR endFmt[] = { '%','0','2','x',0 };
815 DWORD i;
816 LPWSTR ptr = pbFormat;
818 *pcbFormat = bytesNeeded;
819 if (cbEncoded)
821 for (i = 0; i < cbEncoded; i++)
823 if (i < cbEncoded - 1)
824 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
825 else
826 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
829 else
830 *ptr = 0;
831 ret = TRUE;
833 return ret;
836 #define MAX_STRING_RESOURCE_LEN 128
838 static const WCHAR commaSpace[] = { ',',' ',0 };
840 struct BitToString
842 BYTE bit;
843 int id;
844 WCHAR str[MAX_STRING_RESOURCE_LEN];
847 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
848 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
850 DWORD bytesNeeded = sizeof(WCHAR);
851 unsigned int i;
852 BOOL ret = TRUE, localFirst = *first;
854 for (i = 0; i < mapEntries; i++)
855 if (bits & map[i].bit)
857 if (!localFirst)
858 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
859 localFirst = FALSE;
860 bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
862 if (!pbFormat)
864 *first = localFirst;
865 *pcbFormat = bytesNeeded;
867 else if (*pcbFormat < bytesNeeded)
869 *first = localFirst;
870 *pcbFormat = bytesNeeded;
871 SetLastError(ERROR_MORE_DATA);
872 ret = FALSE;
874 else
876 LPWSTR str = pbFormat;
878 localFirst = *first;
879 *pcbFormat = bytesNeeded;
880 for (i = 0; i < mapEntries; i++)
881 if (bits & map[i].bit)
883 if (!localFirst)
885 strcpyW(str, commaSpace);
886 str += strlenW(commaSpace);
888 localFirst = FALSE;
889 strcpyW(str, map[i].str);
890 str += strlenW(map[i].str);
892 *first = localFirst;
894 return ret;
897 static struct BitToString keyUsageByte0Map[] = {
898 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
899 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
900 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
901 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
902 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
903 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
904 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
905 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
906 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
908 static struct BitToString keyUsageByte1Map[] = {
909 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
912 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
913 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
914 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
915 DWORD *pcbFormat)
917 DWORD size;
918 CRYPT_BIT_BLOB *bits;
919 BOOL ret;
921 if (!cbEncoded)
923 SetLastError(E_INVALIDARG);
924 return FALSE;
926 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
927 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
929 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
930 DWORD bytesNeeded = sizeof(WCHAR);
932 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
933 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
934 if (!bits->cbData || bits->cbData > 2)
936 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
937 if (!pbFormat)
938 *pcbFormat = bytesNeeded;
939 else if (*pcbFormat < bytesNeeded)
941 *pcbFormat = bytesNeeded;
942 SetLastError(ERROR_MORE_DATA);
943 ret = FALSE;
945 else
947 LPWSTR str = pbFormat;
949 *pcbFormat = bytesNeeded;
950 strcpyW(str, infoNotAvailable);
953 else
955 static BOOL stringsLoaded = FALSE;
956 unsigned int i;
957 DWORD bitStringLen;
958 BOOL first = TRUE;
960 if (!stringsLoaded)
962 for (i = 0;
963 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
964 i++)
965 LoadStringW(hInstance, keyUsageByte0Map[i].id,
966 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
967 for (i = 0;
968 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
969 i++)
970 LoadStringW(hInstance, keyUsageByte1Map[i].id,
971 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
972 stringsLoaded = TRUE;
974 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
975 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
976 NULL, &bitStringLen, &first);
977 bytesNeeded += bitStringLen;
978 if (bits->cbData == 2)
980 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
981 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
982 NULL, &bitStringLen, &first);
983 bytesNeeded += bitStringLen;
985 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
986 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
987 bits->cbData, NULL, &size);
988 bytesNeeded += size;
989 if (!pbFormat)
990 *pcbFormat = bytesNeeded;
991 else if (*pcbFormat < bytesNeeded)
993 *pcbFormat = bytesNeeded;
994 SetLastError(ERROR_MORE_DATA);
995 ret = FALSE;
997 else
999 LPWSTR str = pbFormat;
1001 bitStringLen = bytesNeeded;
1002 first = TRUE;
1003 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
1004 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
1005 str, &bitStringLen, &first);
1006 str += bitStringLen / sizeof(WCHAR) - 1;
1007 if (bits->cbData == 2)
1009 bitStringLen = bytesNeeded;
1010 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
1011 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
1012 str, &bitStringLen, &first);
1013 str += bitStringLen / sizeof(WCHAR) - 1;
1015 *str++ = ' ';
1016 *str++ = '(';
1017 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1018 bits->cbData, str, &size);
1019 str += size / sizeof(WCHAR) - 1;
1020 *str++ = ')';
1021 *str = 0;
1024 LocalFree(bits);
1026 return ret;
1029 static const WCHAR crlf[] = { '\r','\n',0 };
1031 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1032 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1033 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1034 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1036 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1037 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1038 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1039 DWORD *pcbFormat)
1041 DWORD size;
1042 CERT_BASIC_CONSTRAINTS2_INFO *info;
1043 BOOL ret;
1045 if (!cbEncoded)
1047 SetLastError(E_INVALIDARG);
1048 return FALSE;
1050 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1051 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1053 static const WCHAR pathFmt[] = { '%','d',0 };
1054 static BOOL stringsLoaded = FALSE;
1055 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1056 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1057 LPCWSTR sep, subjectType;
1058 DWORD sepLen;
1060 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1062 sep = crlf;
1063 sepLen = strlenW(crlf) * sizeof(WCHAR);
1065 else
1067 sep = commaSpace;
1068 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1071 if (!stringsLoaded)
1073 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
1074 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
1075 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
1076 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
1077 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
1078 subjectTypeEndCert,
1079 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
1080 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
1081 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
1082 stringsLoaded = TRUE;
1084 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
1085 if (info->fCA)
1086 subjectType = subjectTypeCA;
1087 else
1088 subjectType = subjectTypeEndCert;
1089 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
1090 bytesNeeded += sepLen;
1091 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
1092 if (info->fPathLenConstraint)
1093 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
1094 else
1095 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
1096 sizeof(pathLength) / sizeof(pathLength[0]));
1097 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
1098 if (!pbFormat)
1099 *pcbFormat = bytesNeeded;
1100 else if (*pcbFormat < bytesNeeded)
1102 *pcbFormat = bytesNeeded;
1103 SetLastError(ERROR_MORE_DATA);
1104 ret = FALSE;
1106 else
1108 LPWSTR str = pbFormat;
1110 *pcbFormat = bytesNeeded;
1111 strcpyW(str, subjectTypeHeader);
1112 str += strlenW(subjectTypeHeader);
1113 strcpyW(str, subjectType);
1114 str += strlenW(subjectType);
1115 strcpyW(str, sep);
1116 str += sepLen / sizeof(WCHAR);
1117 strcpyW(str, pathLengthHeader);
1118 str += strlenW(pathLengthHeader);
1119 strcpyW(str, pathLength);
1121 LocalFree(info);
1123 return ret;
1126 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1127 LPWSTR str, DWORD *pcbStr)
1129 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1130 DWORD bytesNeeded;
1131 BOOL ret;
1133 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1134 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1135 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1136 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1137 if (!str)
1139 *pcbStr = bytesNeeded;
1140 ret = TRUE;
1142 else if (*pcbStr < bytesNeeded)
1144 *pcbStr = bytesNeeded;
1145 SetLastError(ERROR_MORE_DATA);
1146 ret = FALSE;
1148 else
1150 *pcbStr = bytesNeeded;
1151 strcpyW(str, buf);
1152 str += strlenW(str);
1153 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1154 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1155 blob->pbData, blob->cbData, str, &bytesNeeded);
1157 return ret;
1160 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1161 DWORD *pcbStr)
1163 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1166 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1167 DWORD *pcbStr)
1169 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1170 str, pcbStr);
1173 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
1174 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
1176 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1177 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1179 BOOL ret;
1180 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1181 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1182 WCHAR ipAddrBuf[32];
1183 WCHAR maskBuf[16];
1184 DWORD bytesNeeded = sizeof(WCHAR);
1185 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1187 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1188 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1189 switch (entry->dwAltNameChoice)
1191 case CERT_ALT_NAME_RFC822_NAME:
1192 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
1193 sizeof(buf) / sizeof(buf[0]));
1194 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
1195 ret = TRUE;
1196 break;
1197 case CERT_ALT_NAME_DNS_NAME:
1198 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
1199 sizeof(buf) / sizeof(buf[0]));
1200 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
1201 ret = TRUE;
1202 break;
1203 case CERT_ALT_NAME_DIRECTORY_NAME:
1205 DWORD directoryNameLen;
1207 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1208 strType |= CERT_NAME_STR_CRLF_FLAG;
1209 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1210 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
1211 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
1212 sizeof(buf) / sizeof(buf[0]));
1213 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1214 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1215 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
1216 else
1217 bytesNeeded += sizeof(WCHAR); /* '=' */
1218 ret = TRUE;
1219 break;
1221 case CERT_ALT_NAME_URL:
1222 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
1223 sizeof(buf) / sizeof(buf[0]));
1224 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
1225 ret = TRUE;
1226 break;
1227 case CERT_ALT_NAME_IP_ADDRESS:
1229 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1230 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1232 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1233 '.','%','d',0 };
1235 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1236 sizeof(buf) / sizeof(buf[0]));
1237 if (entry->u.IPAddress.cbData == 8)
1239 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1241 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1242 sizeof(mask) / sizeof(mask[0]));
1243 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1244 sprintfW(ipAddrBuf, ipAddrFmt,
1245 entry->u.IPAddress.pbData[0],
1246 entry->u.IPAddress.pbData[1],
1247 entry->u.IPAddress.pbData[2],
1248 entry->u.IPAddress.pbData[3]);
1249 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1250 /* indent again, for the mask line */
1251 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1252 sprintfW(maskBuf, ipAddrFmt,
1253 entry->u.IPAddress.pbData[4],
1254 entry->u.IPAddress.pbData[5],
1255 entry->u.IPAddress.pbData[6],
1256 entry->u.IPAddress.pbData[7]);
1257 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1258 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1260 else
1262 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1263 entry->u.IPAddress.pbData[0],
1264 entry->u.IPAddress.pbData[1],
1265 entry->u.IPAddress.pbData[2],
1266 entry->u.IPAddress.pbData[3],
1267 entry->u.IPAddress.pbData[4],
1268 entry->u.IPAddress.pbData[5],
1269 entry->u.IPAddress.pbData[6],
1270 entry->u.IPAddress.pbData[7]);
1271 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1273 ret = TRUE;
1275 else
1277 FIXME("unknown IP address format (%d bytes)\n",
1278 entry->u.IPAddress.cbData);
1279 ret = FALSE;
1281 break;
1283 default:
1284 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1285 ret = FALSE;
1287 if (ret)
1289 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1290 if (!str)
1291 *pcbStr = bytesNeeded;
1292 else if (*pcbStr < bytesNeeded)
1294 *pcbStr = bytesNeeded;
1295 SetLastError(ERROR_MORE_DATA);
1296 ret = FALSE;
1298 else
1300 DWORD i;
1302 *pcbStr = bytesNeeded;
1303 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1305 for (i = 0; i < indentLevel; i++)
1307 strcpyW(str, indent);
1308 str += strlenW(indent);
1311 strcpyW(str, buf);
1312 str += strlenW(str);
1313 switch (entry->dwAltNameChoice)
1315 case CERT_ALT_NAME_RFC822_NAME:
1316 case CERT_ALT_NAME_DNS_NAME:
1317 case CERT_ALT_NAME_URL:
1318 strcpyW(str, entry->u.pwszURL);
1319 break;
1320 case CERT_ALT_NAME_DIRECTORY_NAME:
1321 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1323 strcpyW(str, colonCrlf);
1324 str += strlenW(colonCrlf);
1326 else
1327 *str++ = '=';
1328 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1329 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1330 bytesNeeded / sizeof(WCHAR));
1331 break;
1332 case CERT_ALT_NAME_IP_ADDRESS:
1333 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1335 strcpyW(str, ipAddrBuf);
1336 str += strlenW(ipAddrBuf);
1337 strcpyW(str, crlf);
1338 str += strlenW(crlf);
1339 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1341 for (i = 0; i < indentLevel; i++)
1343 strcpyW(str, indent);
1344 str += strlenW(indent);
1347 strcpyW(str, mask);
1348 str += strlenW(mask);
1349 strcpyW(str, maskBuf);
1351 else
1352 strcpyW(str, ipAddrBuf);
1353 break;
1357 return ret;
1360 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1361 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1363 DWORD i, size, bytesNeeded = 0;
1364 BOOL ret = TRUE;
1365 LPCWSTR sep;
1366 DWORD sepLen;
1368 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1370 sep = crlf;
1371 sepLen = strlenW(crlf) * sizeof(WCHAR);
1373 else
1375 sep = commaSpace;
1376 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1379 for (i = 0; ret && i < name->cAltEntry; i++)
1381 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1382 &name->rgAltEntry[i], NULL, &size);
1383 if (ret)
1385 bytesNeeded += size - sizeof(WCHAR);
1386 if (i < name->cAltEntry - 1)
1387 bytesNeeded += sepLen;
1390 if (ret)
1392 bytesNeeded += sizeof(WCHAR);
1393 if (!str)
1394 *pcbStr = bytesNeeded;
1395 else if (*pcbStr < bytesNeeded)
1397 *pcbStr = bytesNeeded;
1398 SetLastError(ERROR_MORE_DATA);
1399 ret = FALSE;
1401 else
1403 *pcbStr = bytesNeeded;
1404 for (i = 0; ret && i < name->cAltEntry; i++)
1406 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1407 &name->rgAltEntry[i], str, &size);
1408 if (ret)
1410 str += size / sizeof(WCHAR) - 1;
1411 if (i < name->cAltEntry - 1)
1413 strcpyW(str, sep);
1414 str += sepLen / sizeof(WCHAR);
1420 return ret;
1423 static const WCHAR colonSep[] = { ':',' ',0 };
1425 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1426 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1427 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1428 DWORD *pcbFormat)
1430 BOOL ret;
1431 CERT_ALT_NAME_INFO *info;
1432 DWORD size;
1434 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1435 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1437 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1438 LocalFree(info);
1440 return ret;
1443 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1444 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1446 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1447 DWORD bytesNeeded, sepLen;
1448 LPCWSTR sep;
1449 BOOL ret;
1451 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1452 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1453 &bytesNeeded);
1454 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1455 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1457 sep = colonCrlf;
1458 sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1460 else
1462 sep = colonSep;
1463 sepLen = strlenW(colonSep) * sizeof(WCHAR);
1465 bytesNeeded += sepLen;
1466 if (ret)
1468 if (!str)
1469 *pcbStr = bytesNeeded;
1470 else if (*pcbStr < bytesNeeded)
1472 *pcbStr = bytesNeeded;
1473 SetLastError(ERROR_MORE_DATA);
1474 ret = FALSE;
1476 else
1478 *pcbStr = bytesNeeded;
1479 strcpyW(str, buf);
1480 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1481 str += strlenW(str);
1482 strcpyW(str, sep);
1483 str += sepLen / sizeof(WCHAR);
1484 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1485 &bytesNeeded);
1488 return ret;
1491 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1492 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1493 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1494 DWORD *pcbFormat)
1496 CERT_AUTHORITY_KEY_ID2_INFO *info;
1497 DWORD size;
1498 BOOL ret = FALSE;
1500 if (!cbEncoded)
1502 SetLastError(E_INVALIDARG);
1503 return FALSE;
1505 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1506 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1508 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1509 LPCWSTR sep;
1510 DWORD sepLen;
1511 BOOL needSeparator = FALSE;
1513 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1515 sep = crlf;
1516 sepLen = strlenW(crlf) * sizeof(WCHAR);
1518 else
1520 sep = commaSpace;
1521 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1524 if (info->KeyId.cbData)
1526 needSeparator = TRUE;
1527 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1528 if (ret)
1530 /* don't include NULL-terminator more than once */
1531 bytesNeeded += size - sizeof(WCHAR);
1534 if (info->AuthorityCertIssuer.cAltEntry)
1536 if (needSeparator)
1537 bytesNeeded += sepLen;
1538 needSeparator = TRUE;
1539 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1540 &info->AuthorityCertIssuer, NULL, &size);
1541 if (ret)
1543 /* don't include NULL-terminator more than once */
1544 bytesNeeded += size - sizeof(WCHAR);
1547 if (info->AuthorityCertSerialNumber.cbData)
1549 if (needSeparator)
1550 bytesNeeded += sepLen;
1551 ret = CRYPT_FormatCertSerialNumber(
1552 &info->AuthorityCertSerialNumber, NULL, &size);
1553 if (ret)
1555 /* don't include NULL-terminator more than once */
1556 bytesNeeded += size - sizeof(WCHAR);
1559 if (ret)
1561 if (!pbFormat)
1562 *pcbFormat = bytesNeeded;
1563 else if (*pcbFormat < bytesNeeded)
1565 *pcbFormat = bytesNeeded;
1566 SetLastError(ERROR_MORE_DATA);
1567 ret = FALSE;
1569 else
1571 LPWSTR str = pbFormat;
1573 *pcbFormat = bytesNeeded;
1574 needSeparator = FALSE;
1575 if (info->KeyId.cbData)
1577 needSeparator = TRUE;
1578 /* Overestimate size available, it's already been checked
1579 * above.
1581 size = bytesNeeded;
1582 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1583 if (ret)
1584 str += size / sizeof(WCHAR) - 1;
1586 if (info->AuthorityCertIssuer.cAltEntry)
1588 if (needSeparator)
1590 strcpyW(str, sep);
1591 str += sepLen / sizeof(WCHAR);
1593 needSeparator = TRUE;
1594 /* Overestimate size available, it's already been checked
1595 * above.
1597 size = bytesNeeded;
1598 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1599 &info->AuthorityCertIssuer, str, &size);
1600 if (ret)
1601 str += size / sizeof(WCHAR) - 1;
1603 if (info->AuthorityCertSerialNumber.cbData)
1605 if (needSeparator)
1607 strcpyW(str, sep);
1608 str += sepLen / sizeof(WCHAR);
1610 /* Overestimate size available, it's already been checked
1611 * above.
1613 size = bytesNeeded;
1614 ret = CRYPT_FormatCertSerialNumber(
1615 &info->AuthorityCertSerialNumber, str, &size);
1619 LocalFree(info);
1621 return ret;
1624 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1625 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1626 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1627 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1628 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1629 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1631 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1632 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1633 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1634 DWORD *pcbFormat)
1636 CERT_AUTHORITY_INFO_ACCESS *info;
1637 DWORD size;
1638 BOOL ret = FALSE;
1640 if (!cbEncoded)
1642 SetLastError(E_INVALIDARG);
1643 return FALSE;
1645 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1646 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1647 NULL, &info, &size)))
1649 DWORD bytesNeeded = sizeof(WCHAR);
1651 if (!info->cAccDescr)
1653 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1655 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1656 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1657 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1658 if (!pbFormat)
1659 *pcbFormat = bytesNeeded;
1660 else if (*pcbFormat < bytesNeeded)
1662 *pcbFormat = bytesNeeded;
1663 SetLastError(ERROR_MORE_DATA);
1664 ret = FALSE;
1666 else
1668 *pcbFormat = bytesNeeded;
1669 strcpyW(pbFormat, infoNotAvailable);
1672 else
1674 static const WCHAR numFmt[] = { '%','d',0 };
1675 static const WCHAR equal[] = { '=',0 };
1676 static BOOL stringsLoaded = FALSE;
1677 DWORD i;
1678 LPCWSTR headingSep, accessMethodSep, locationSep;
1679 WCHAR accessDescrNum[11];
1681 if (!stringsLoaded)
1683 LoadStringW(hInstance, IDS_AIA, aia,
1684 sizeof(aia) / sizeof(aia[0]));
1685 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1686 sizeof(accessMethod) / sizeof(accessMethod[0]));
1687 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1688 sizeof(ocsp) / sizeof(ocsp[0]));
1689 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1690 sizeof(caIssuers) / sizeof(caIssuers[0]));
1691 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1692 sizeof(unknown) / sizeof(unknown[0]));
1693 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1694 sizeof(accessLocation) / sizeof(accessLocation[0]));
1695 stringsLoaded = TRUE;
1697 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1699 headingSep = crlf;
1700 accessMethodSep = crlf;
1701 locationSep = colonCrlf;
1703 else
1705 headingSep = colonSep;
1706 accessMethodSep = commaSpace;
1707 locationSep = equal;
1710 for (i = 0; ret && i < info->cAccDescr; i++)
1712 /* Heading */
1713 bytesNeeded += sizeof(WCHAR); /* left bracket */
1714 sprintfW(accessDescrNum, numFmt, i + 1);
1715 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1716 bytesNeeded += sizeof(WCHAR); /* right bracket */
1717 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1718 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1719 /* Access method */
1720 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1721 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1722 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1723 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1724 szOID_PKIX_OCSP))
1725 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1726 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1727 szOID_PKIX_CA_ISSUERS))
1728 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1729 else
1730 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1731 bytesNeeded += sizeof(WCHAR); /* space */
1732 bytesNeeded += sizeof(WCHAR); /* left paren */
1733 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1734 * sizeof(WCHAR);
1735 bytesNeeded += sizeof(WCHAR); /* right paren */
1736 /* Delimiter between access method and location */
1737 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1738 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1739 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1740 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1741 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1742 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1743 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1744 if (ret)
1745 bytesNeeded += size - sizeof(WCHAR);
1746 /* Need extra delimiter between access method entries */
1747 if (i < info->cAccDescr - 1)
1748 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1750 if (ret)
1752 if (!pbFormat)
1753 *pcbFormat = bytesNeeded;
1754 else if (*pcbFormat < bytesNeeded)
1756 *pcbFormat = bytesNeeded;
1757 SetLastError(ERROR_MORE_DATA);
1758 ret = FALSE;
1760 else
1762 LPWSTR str = pbFormat;
1763 DWORD altNameEntrySize;
1765 *pcbFormat = bytesNeeded;
1766 for (i = 0; ret && i < info->cAccDescr; i++)
1768 LPCSTR oidPtr;
1770 *str++ = '[';
1771 sprintfW(accessDescrNum, numFmt, i + 1);
1772 strcpyW(str, accessDescrNum);
1773 str += strlenW(accessDescrNum);
1774 *str++ = ']';
1775 strcpyW(str, aia);
1776 str += strlenW(aia);
1777 strcpyW(str, headingSep);
1778 str += strlenW(headingSep);
1779 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1781 strcpyW(str, indent);
1782 str += strlenW(indent);
1784 strcpyW(str, accessMethod);
1785 str += strlenW(accessMethod);
1786 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1787 szOID_PKIX_OCSP))
1789 strcpyW(str, ocsp);
1790 str += strlenW(ocsp);
1792 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1793 szOID_PKIX_CA_ISSUERS))
1795 strcpyW(str, caIssuers);
1796 str += strlenW(caIssuers);
1798 else
1800 strcpyW(str, unknown);
1801 str += strlenW(unknown);
1803 *str++ = ' ';
1804 *str++ = '(';
1805 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1806 *oidPtr; oidPtr++, str++)
1807 *str = *oidPtr;
1808 *str++ = ')';
1809 strcpyW(str, accessMethodSep);
1810 str += strlenW(accessMethodSep);
1811 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1813 strcpyW(str, indent);
1814 str += strlenW(indent);
1816 strcpyW(str, accessLocation);
1817 str += strlenW(accessLocation);
1818 strcpyW(str, locationSep);
1819 str += strlenW(locationSep);
1820 /* This overestimates the size available, but that
1821 * won't matter since we checked earlier whether enough
1822 * space for the entire string was available.
1824 altNameEntrySize = bytesNeeded;
1825 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1826 &info->rgAccDescr[i].AccessLocation, str,
1827 &altNameEntrySize);
1828 if (ret)
1829 str += altNameEntrySize / sizeof(WCHAR) - 1;
1830 if (i < info->cAccDescr - 1)
1832 strcpyW(str, accessMethodSep);
1833 str += strlenW(accessMethodSep);
1839 LocalFree(info);
1841 return ret;
1844 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1845 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1846 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1847 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1848 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1849 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1851 struct reason_map_entry
1853 BYTE reasonBit;
1854 LPWSTR reason;
1855 int id;
1857 static struct reason_map_entry reason_map[] = {
1858 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1859 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1860 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1861 IDS_REASON_AFFILIATION_CHANGED },
1862 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1863 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1864 IDS_REASON_CESSATION_OF_OPERATION },
1865 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1866 IDS_REASON_CERTIFICATE_HOLD },
1869 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1870 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1872 static const WCHAR sep[] = { ',',' ',0 };
1873 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1874 static BOOL stringsLoaded = FALSE;
1875 unsigned int i, numReasons = 0;
1876 BOOL ret = TRUE;
1877 DWORD bytesNeeded = sizeof(WCHAR);
1878 WCHAR bits[6];
1880 if (!stringsLoaded)
1882 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1883 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1884 MAX_STRING_RESOURCE_LEN);
1885 stringsLoaded = TRUE;
1887 /* No need to check reasonFlags->cbData, we already know it's positive.
1888 * Ignore any other bytes, as they're for undefined bits.
1890 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1892 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1894 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1895 if (numReasons++)
1896 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1899 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1900 bytesNeeded += strlenW(bits);
1901 if (!str)
1902 *pcbStr = bytesNeeded;
1903 else if (*pcbStr < bytesNeeded)
1905 *pcbStr = bytesNeeded;
1906 SetLastError(ERROR_MORE_DATA);
1907 ret = FALSE;
1909 else
1911 *pcbStr = bytesNeeded;
1912 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1914 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1916 strcpyW(str, reason_map[i].reason);
1917 str += strlenW(reason_map[i].reason);
1918 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1919 numReasons)
1921 strcpyW(str, sep);
1922 str += strlenW(sep);
1926 strcpyW(str, bits);
1928 return ret;
1931 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1932 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1933 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1934 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1935 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1936 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1938 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1939 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1940 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1941 DWORD *pcbFormat)
1943 CRL_DIST_POINTS_INFO *info;
1944 DWORD size;
1945 BOOL ret = FALSE;
1947 if (!cbEncoded)
1949 SetLastError(E_INVALIDARG);
1950 return FALSE;
1952 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1953 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1955 static const WCHAR numFmt[] = { '%','d',0 };
1956 static const WCHAR colon[] = { ':',0 };
1957 static BOOL stringsLoaded = FALSE;
1958 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1959 BOOL haveAnEntry = FALSE;
1960 LPCWSTR headingSep, nameSep;
1961 WCHAR distPointNum[11];
1962 DWORD i;
1964 if (!stringsLoaded)
1966 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1967 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1968 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1969 sizeof(distPointName) / sizeof(distPointName[0]));
1970 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1971 sizeof(fullName) / sizeof(fullName[0]));
1972 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1973 sizeof(rdnName) / sizeof(rdnName[0]));
1974 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1975 sizeof(reason) / sizeof(reason[0]));
1976 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1977 sizeof(issuer) / sizeof(issuer[0]));
1978 stringsLoaded = TRUE;
1980 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1982 headingSep = crlf;
1983 nameSep = colonCrlf;
1985 else
1987 headingSep = colonSep;
1988 nameSep = colon;
1991 for (i = 0; ret && i < info->cDistPoint; i++)
1993 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1995 if (distPoint->DistPointName.dwDistPointNameChoice !=
1996 CRL_DIST_POINT_NO_NAME)
1998 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1999 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2000 if (distPoint->DistPointName.dwDistPointNameChoice ==
2001 CRL_DIST_POINT_FULL_NAME)
2002 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
2003 else
2004 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
2005 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2006 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2007 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
2008 /* The indent level (3) is higher than when used as the issuer,
2009 * because the name is subordinate to the name type (full vs.
2010 * RDN.)
2012 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2013 &distPoint->DistPointName.u.FullName, NULL, &size);
2014 if (ret)
2015 bytesNeeded += size - sizeof(WCHAR);
2016 haveAnEntry = TRUE;
2018 else if (distPoint->ReasonFlags.cbData)
2020 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
2021 ret = CRYPT_FormatReason(dwFormatStrType,
2022 &distPoint->ReasonFlags, NULL, &size);
2023 if (ret)
2024 bytesNeeded += size - sizeof(WCHAR);
2025 haveAnEntry = TRUE;
2027 else if (distPoint->CRLIssuer.cAltEntry)
2029 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
2030 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2031 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2032 &distPoint->CRLIssuer, NULL, &size);
2033 if (ret)
2034 bytesNeeded += size - sizeof(WCHAR);
2035 haveAnEntry = TRUE;
2037 if (haveAnEntry)
2039 bytesNeeded += sizeof(WCHAR); /* left bracket */
2040 sprintfW(distPointNum, numFmt, i + 1);
2041 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
2042 bytesNeeded += sizeof(WCHAR); /* right bracket */
2043 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
2044 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
2045 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2046 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
2049 if (!haveAnEntry)
2051 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2053 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2054 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2055 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2056 if (!pbFormat)
2057 *pcbFormat = bytesNeeded;
2058 else if (*pcbFormat < bytesNeeded)
2060 *pcbFormat = bytesNeeded;
2061 SetLastError(ERROR_MORE_DATA);
2062 ret = FALSE;
2064 else
2066 *pcbFormat = bytesNeeded;
2067 strcpyW(pbFormat, infoNotAvailable);
2070 else
2072 if (!pbFormat)
2073 *pcbFormat = bytesNeeded;
2074 else if (*pcbFormat < bytesNeeded)
2076 *pcbFormat = bytesNeeded;
2077 SetLastError(ERROR_MORE_DATA);
2078 ret = FALSE;
2080 else
2082 LPWSTR str = pbFormat;
2084 *pcbFormat = bytesNeeded;
2085 for (i = 0; ret && i < info->cDistPoint; i++)
2087 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2089 *str++ = '[';
2090 sprintfW(distPointNum, numFmt, i + 1);
2091 strcpyW(str, distPointNum);
2092 str += strlenW(distPointNum);
2093 *str++ = ']';
2094 strcpyW(str, crlDistPoint);
2095 str += strlenW(crlDistPoint);
2096 strcpyW(str, headingSep);
2097 str += strlenW(headingSep);
2098 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2100 strcpyW(str, indent);
2101 str += strlenW(indent);
2103 if (distPoint->DistPointName.dwDistPointNameChoice !=
2104 CRL_DIST_POINT_NO_NAME)
2106 DWORD altNameSize = bytesNeeded;
2108 strcpyW(str, distPointName);
2109 str += strlenW(distPointName);
2110 strcpyW(str, nameSep);
2111 str += strlenW(nameSep);
2112 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2114 strcpyW(str, indent);
2115 str += strlenW(indent);
2116 strcpyW(str, indent);
2117 str += strlenW(indent);
2119 if (distPoint->DistPointName.dwDistPointNameChoice ==
2120 CRL_DIST_POINT_FULL_NAME)
2122 strcpyW(str, fullName);
2123 str += strlenW(fullName);
2125 else
2127 strcpyW(str, rdnName);
2128 str += strlenW(rdnName);
2130 strcpyW(str, nameSep);
2131 str += strlenW(nameSep);
2132 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2133 &distPoint->DistPointName.u.FullName, str,
2134 &altNameSize);
2135 if (ret)
2136 str += altNameSize / sizeof(WCHAR) - 1;
2138 else if (distPoint->ReasonFlags.cbData)
2140 DWORD reasonSize = bytesNeeded;
2142 strcpyW(str, reason);
2143 str += strlenW(reason);
2144 ret = CRYPT_FormatReason(dwFormatStrType,
2145 &distPoint->ReasonFlags, str, &reasonSize);
2146 if (ret)
2147 str += reasonSize / sizeof(WCHAR) - 1;
2149 else if (distPoint->CRLIssuer.cAltEntry)
2151 DWORD crlIssuerSize = bytesNeeded;
2153 strcpyW(str, issuer);
2154 str += strlenW(issuer);
2155 strcpyW(str, nameSep);
2156 str += strlenW(nameSep);
2157 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2158 &distPoint->CRLIssuer, str,
2159 &crlIssuerSize);
2160 if (ret)
2161 str += crlIssuerSize / sizeof(WCHAR) - 1;
2166 LocalFree(info);
2168 return ret;
2171 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2172 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2173 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2174 DWORD *pcbFormat)
2176 CERT_ENHKEY_USAGE *usage;
2177 DWORD size;
2178 BOOL ret = FALSE;
2180 if (!cbEncoded)
2182 SetLastError(E_INVALIDARG);
2183 return FALSE;
2185 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2186 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2188 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2189 DWORD i;
2190 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2191 LPCWSTR sep;
2192 DWORD sepLen;
2194 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2196 sep = crlf;
2197 sepLen = strlenW(crlf) * sizeof(WCHAR);
2199 else
2201 sep = commaSpace;
2202 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2205 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
2206 sizeof(unknown) / sizeof(unknown[0]));
2207 for (i = 0; i < usage->cUsageIdentifier; i++)
2209 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2210 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2212 if (info)
2213 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
2214 else
2215 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
2216 bytesNeeded += sizeof(WCHAR); /* space */
2217 bytesNeeded += sizeof(WCHAR); /* left paren */
2218 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
2219 sizeof(WCHAR);
2220 bytesNeeded += sizeof(WCHAR); /* right paren */
2221 if (i < usage->cUsageIdentifier - 1)
2222 bytesNeeded += sepLen;
2224 if (!pbFormat)
2225 *pcbFormat = bytesNeeded;
2226 else if (*pcbFormat < bytesNeeded)
2228 *pcbFormat = bytesNeeded;
2229 SetLastError(ERROR_MORE_DATA);
2230 ret = FALSE;
2232 else
2234 LPWSTR str = pbFormat;
2236 *pcbFormat = bytesNeeded;
2237 for (i = 0; i < usage->cUsageIdentifier; i++)
2239 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2240 usage->rgpszUsageIdentifier[i],
2241 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2242 LPCSTR oidPtr;
2244 if (info)
2246 strcpyW(str, info->pwszName);
2247 str += strlenW(info->pwszName);
2249 else
2251 strcpyW(str, unknown);
2252 str += strlenW(unknown);
2254 *str++ = ' ';
2255 *str++ = '(';
2256 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2257 *str++ = *oidPtr;
2258 *str++ = ')';
2259 *str = 0;
2260 if (i < usage->cUsageIdentifier - 1)
2262 strcpyW(str, sep);
2263 str += sepLen / sizeof(WCHAR);
2267 LocalFree(usage);
2269 return ret;
2272 static struct BitToString netscapeCertTypeMap[] = {
2273 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2274 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2275 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2276 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2277 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2278 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2279 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2282 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2283 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2284 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2285 DWORD *pcbFormat)
2287 DWORD size;
2288 CRYPT_BIT_BLOB *bits;
2289 BOOL ret;
2291 if (!cbEncoded)
2293 SetLastError(E_INVALIDARG);
2294 return FALSE;
2296 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2297 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2299 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2300 DWORD bytesNeeded = sizeof(WCHAR);
2302 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2303 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2304 if (!bits->cbData || bits->cbData > 1)
2306 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2307 if (!pbFormat)
2308 *pcbFormat = bytesNeeded;
2309 else if (*pcbFormat < bytesNeeded)
2311 *pcbFormat = bytesNeeded;
2312 SetLastError(ERROR_MORE_DATA);
2313 ret = FALSE;
2315 else
2317 LPWSTR str = pbFormat;
2319 *pcbFormat = bytesNeeded;
2320 strcpyW(str, infoNotAvailable);
2323 else
2325 static BOOL stringsLoaded = FALSE;
2326 unsigned int i;
2327 DWORD bitStringLen;
2328 BOOL first = TRUE;
2330 if (!stringsLoaded)
2332 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2333 sizeof(netscapeCertTypeMap[0]); i++)
2334 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2335 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2336 stringsLoaded = TRUE;
2338 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2339 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2340 NULL, &bitStringLen, &first);
2341 bytesNeeded += bitStringLen;
2342 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2343 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2344 bits->cbData, NULL, &size);
2345 bytesNeeded += size;
2346 if (!pbFormat)
2347 *pcbFormat = bytesNeeded;
2348 else if (*pcbFormat < bytesNeeded)
2350 *pcbFormat = bytesNeeded;
2351 SetLastError(ERROR_MORE_DATA);
2352 ret = FALSE;
2354 else
2356 LPWSTR str = pbFormat;
2358 bitStringLen = bytesNeeded;
2359 first = TRUE;
2360 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2361 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2362 str, &bitStringLen, &first);
2363 str += bitStringLen / sizeof(WCHAR) - 1;
2364 *str++ = ' ';
2365 *str++ = '(';
2366 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2367 bits->cbData, str, &size);
2368 str += size / sizeof(WCHAR) - 1;
2369 *str++ = ')';
2370 *str = 0;
2373 LocalFree(bits);
2375 return ret;
2378 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2379 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2380 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2381 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2382 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2383 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2385 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2386 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2387 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2388 DWORD *pcbFormat)
2390 SPC_FINANCIAL_CRITERIA criteria;
2391 DWORD size = sizeof(criteria);
2392 BOOL ret = FALSE;
2394 if (!cbEncoded)
2396 SetLastError(E_INVALIDARG);
2397 return FALSE;
2399 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2400 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2401 &size)))
2403 static BOOL stringsLoaded = FALSE;
2404 DWORD bytesNeeded = sizeof(WCHAR);
2405 LPCWSTR sep;
2406 DWORD sepLen;
2408 if (!stringsLoaded)
2410 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2411 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2412 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2413 sizeof(available) / sizeof(available[0]));
2414 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2415 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2416 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2417 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2418 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2419 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2420 stringsLoaded = TRUE;
2422 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2424 sep = crlf;
2425 sepLen = strlenW(crlf) * sizeof(WCHAR);
2427 else
2429 sep = commaSpace;
2430 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2432 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2433 if (criteria.fFinancialInfoAvailable)
2435 bytesNeeded += strlenW(available) * sizeof(WCHAR);
2436 bytesNeeded += sepLen;
2437 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2438 if (criteria.fMeetsCriteria)
2439 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2440 else
2441 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2443 else
2444 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2445 if (!pbFormat)
2446 *pcbFormat = bytesNeeded;
2447 else if (*pcbFormat < bytesNeeded)
2449 *pcbFormat = bytesNeeded;
2450 SetLastError(ERROR_MORE_DATA);
2451 ret = FALSE;
2453 else
2455 LPWSTR str = pbFormat;
2457 *pcbFormat = bytesNeeded;
2458 strcpyW(str, financialCriteria);
2459 str += strlenW(financialCriteria);
2460 if (criteria.fFinancialInfoAvailable)
2462 strcpyW(str, available);
2463 str += strlenW(available);
2464 strcpyW(str, sep);
2465 str += sepLen / sizeof(WCHAR);
2466 strcpyW(str, meetsCriteria);
2467 str += strlenW(meetsCriteria);
2468 if (criteria.fMeetsCriteria)
2469 strcpyW(str, yes);
2470 else
2471 strcpyW(str, no);
2473 else
2475 strcpyW(str, notAvailable);
2479 return ret;
2482 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2483 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2484 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2485 DWORD *pcbFormat)
2487 CERT_NAME_VALUE *value;
2488 DWORD size;
2489 BOOL ret;
2491 if (!cbEncoded)
2493 SetLastError(E_INVALIDARG);
2494 return FALSE;
2496 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2497 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2499 if (!pbFormat)
2500 *pcbFormat = value->Value.cbData;
2501 else if (*pcbFormat < value->Value.cbData)
2503 *pcbFormat = value->Value.cbData;
2504 SetLastError(ERROR_MORE_DATA);
2505 ret = FALSE;
2507 else
2509 LPWSTR str = pbFormat;
2511 *pcbFormat = value->Value.cbData;
2512 strcpyW(str, (LPWSTR)value->Value.pbData);
2515 return ret;
2518 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2519 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2521 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2522 DWORD formatStrType, LPCSTR lpszStructType)
2524 CryptFormatObjectFunc format = NULL;
2526 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2528 SetLastError(ERROR_FILE_NOT_FOUND);
2529 return NULL;
2531 if (IS_INTOID(lpszStructType))
2533 switch (LOWORD(lpszStructType))
2535 case LOWORD(X509_KEY_USAGE):
2536 format = CRYPT_FormatKeyUsage;
2537 break;
2538 case LOWORD(X509_ALTERNATE_NAME):
2539 format = CRYPT_FormatAltName;
2540 break;
2541 case LOWORD(X509_BASIC_CONSTRAINTS2):
2542 format = CRYPT_FormatBasicConstraints2;
2543 break;
2544 case LOWORD(X509_AUTHORITY_KEY_ID2):
2545 format = CRYPT_FormatAuthorityKeyId2;
2546 break;
2547 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2548 format = CRYPT_FormatAuthorityInfoAccess;
2549 break;
2550 case LOWORD(X509_CRL_DIST_POINTS):
2551 format = CRYPT_FormatCRLDistPoints;
2552 break;
2553 case LOWORD(X509_ENHANCED_KEY_USAGE):
2554 format = CRYPT_FormatEnhancedKeyUsage;
2555 break;
2556 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2557 format = CRYPT_FormatSpcFinancialCriteria;
2558 break;
2561 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2562 format = CRYPT_FormatAltName;
2563 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2564 format = CRYPT_FormatAltName;
2565 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2566 format = CRYPT_FormatKeyUsage;
2567 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2568 format = CRYPT_FormatAltName;
2569 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2570 format = CRYPT_FormatAltName;
2571 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2572 format = CRYPT_FormatBasicConstraints2;
2573 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2574 format = CRYPT_FormatAuthorityInfoAccess;
2575 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2576 format = CRYPT_FormatAuthorityKeyId2;
2577 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2578 format = CRYPT_FormatCRLDistPoints;
2579 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2580 format = CRYPT_FormatEnhancedKeyUsage;
2581 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2582 format = CRYPT_FormatNetscapeCertType;
2583 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2584 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2585 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2586 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2587 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2588 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2589 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2590 format = CRYPT_FormatUnicodeString;
2591 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2592 format = CRYPT_FormatSpcFinancialCriteria;
2593 return format;
2596 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2597 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2598 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2600 CryptFormatObjectFunc format = NULL;
2601 HCRYPTOIDFUNCADDR hFunc = NULL;
2602 BOOL ret = FALSE;
2604 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2605 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2606 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2608 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2609 dwFormatStrType, lpszStructType)))
2611 static HCRYPTOIDFUNCSET set = NULL;
2613 if (!set)
2614 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2615 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2616 (void **)&format, &hFunc);
2618 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2619 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2620 format = CRYPT_FormatHexString;
2621 if (format)
2622 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2623 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2624 pcbFormat);
2625 if (hFunc)
2626 CryptFreeOIDFunctionAddress(hFunc, 0);
2627 return ret;