78dea1991c0b4b15dff4f2ab10116da723ce1f77
[reactos.git] / dll / win32 / crypt32 / object.c
1 /*
2 * crypt32 Crypt*Object functions
3 *
4 * Copyright 2007 Juan Lang
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "crypt32_private.h"
22
23 #include <wintrust.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
26
27 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
28 {
29 BOOL ret = FALSE;
30 HANDLE file;
31
32 TRACE("%s\n", debugstr_w(fileName));
33
34 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
35 OPEN_EXISTING, 0, NULL);
36 if (file != INVALID_HANDLE_VALUE)
37 {
38 ret = TRUE;
39 blob->cbData = GetFileSize(file, NULL);
40 if (blob->cbData)
41 {
42 blob->pbData = CryptMemAlloc(blob->cbData);
43 if (blob->pbData)
44 {
45 DWORD read;
46
47 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL) && read == blob->cbData;
48 if (!ret) CryptMemFree(blob->pbData);
49 }
50 else
51 ret = FALSE;
52 }
53 CloseHandle(file);
54 }
55 TRACE("returning %d\n", ret);
56 return ret;
57 }
58
59 static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
60 DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
61 DWORD *contentType, const void **ppvContext)
62 {
63 BOOL ret = FALSE;
64
65 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
66 {
67 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
68 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
69 if (ret && contentType)
70 *contentType = CERT_QUERY_CONTENT_CERT;
71 }
72 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
73 {
74 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
75 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
76 if (ret && contentType)
77 *contentType = CERT_QUERY_CONTENT_CRL;
78 }
79 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
80 {
81 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
82 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
83 if (ret && contentType)
84 *contentType = CERT_QUERY_CONTENT_CTL;
85 }
86 return ret;
87 }
88
89 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
90 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
91 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
92 HCERTSTORE *phCertStore, const void **ppvContext)
93 {
94 CERT_BLOB fileBlob;
95 const CERT_BLOB *blob;
96 HCERTSTORE store;
97 BOOL ret;
98 DWORD formatType = 0;
99
100 switch (dwObjectType)
101 {
102 case CERT_QUERY_OBJECT_FILE:
103 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
104 * just read the file directly
105 */
106 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
107 blob = &fileBlob;
108 break;
109 case CERT_QUERY_OBJECT_BLOB:
110 blob = pvObject;
111 ret = TRUE;
112 break;
113 default:
114 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
115 ret = FALSE;
116 }
117 if (!ret)
118 return FALSE;
119
120 ret = FALSE;
121 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
122 CERT_STORE_CREATE_NEW_FLAG, NULL);
123 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
124 {
125 ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
126 pdwContentType, ppvContext);
127 if (ret)
128 formatType = CERT_QUERY_FORMAT_BINARY;
129 }
130 if (!ret &&
131 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
132 {
133 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
134 CRYPT_DATA_BLOB decoded;
135
136 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
137 trimmed.cbData--;
138 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
139 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
140 if (ret)
141 {
142 decoded.pbData = CryptMemAlloc(decoded.cbData);
143 if (decoded.pbData)
144 {
145 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
146 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
147 &decoded.cbData, NULL, NULL);
148 if (ret)
149 {
150 ret = CRYPT_QueryContextBlob(&decoded,
151 dwExpectedContentTypeFlags, store, pdwContentType,
152 ppvContext);
153 if (ret)
154 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
155 }
156 CryptMemFree(decoded.pbData);
157 }
158 else
159 ret = FALSE;
160 }
161 }
162 if (ret)
163 {
164 if (pdwMsgAndCertEncodingType)
165 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
166 if (pdwFormatType)
167 *pdwFormatType = formatType;
168 if (phCertStore)
169 *phCertStore = CertDuplicateStore(store);
170 }
171 CertCloseStore(store, 0);
172 if (blob == &fileBlob)
173 CryptMemFree(blob->pbData);
174 TRACE("returning %d\n", ret);
175 return ret;
176 }
177
178 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
179 const void *pvObject, DWORD dwExpectedContentTypeFlags,
180 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
181 HCERTSTORE *phCertStore, const void **ppvContext)
182 {
183 CERT_BLOB fileBlob;
184 const CERT_BLOB *blob;
185 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
186 const void *context;
187 DWORD contextType;
188 BOOL ret;
189
190 switch (dwObjectType)
191 {
192 case CERT_QUERY_OBJECT_FILE:
193 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
194 * just read the file directly
195 */
196 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
197 blob = &fileBlob;
198 break;
199 case CERT_QUERY_OBJECT_BLOB:
200 blob = pvObject;
201 ret = TRUE;
202 break;
203 default:
204 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
205 ret = FALSE;
206 }
207 if (!ret)
208 return FALSE;
209
210 ret = FALSE;
211 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
212 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
213 if (context)
214 {
215 DWORD contentType, certStoreOffset;
216
217 ret = TRUE;
218 switch (contextType)
219 {
220 case CERT_STORE_CERTIFICATE_CONTEXT:
221 contextInterface = pCertInterface;
222 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
223 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
224 if (!(dwExpectedContentTypeFlags &
225 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
226 {
227 SetLastError(ERROR_INVALID_DATA);
228 ret = FALSE;
229 goto end;
230 }
231 break;
232 case CERT_STORE_CRL_CONTEXT:
233 contextInterface = pCRLInterface;
234 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
235 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
236 if (!(dwExpectedContentTypeFlags &
237 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
238 {
239 SetLastError(ERROR_INVALID_DATA);
240 ret = FALSE;
241 goto end;
242 }
243 break;
244 case CERT_STORE_CTL_CONTEXT:
245 contextInterface = pCTLInterface;
246 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
247 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
248 if (!(dwExpectedContentTypeFlags &
249 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
250 {
251 SetLastError(ERROR_INVALID_DATA);
252 ret = FALSE;
253 goto end;
254 }
255 break;
256 default:
257 SetLastError(ERROR_INVALID_DATA);
258 ret = FALSE;
259 goto end;
260 }
261 if (pdwMsgAndCertEncodingType)
262 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
263 if (pdwContentType)
264 *pdwContentType = contentType;
265 if (phCertStore)
266 *phCertStore = CertDuplicateStore(
267 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
268 if (ppvContext)
269 {
270 *ppvContext = context;
271 Context_AddRef(context_from_ptr(context));
272 }
273 }
274
275 end:
276 if (contextInterface && context)
277 Context_Release(context_from_ptr(context));
278 if (blob == &fileBlob)
279 CryptMemFree(blob->pbData);
280 TRACE("returning %d\n", ret);
281 return ret;
282 }
283
284 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
285 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
286 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
287 {
288 HANDLE file;
289 BOOL ret = FALSE;
290
291 TRACE("%s\n", debugstr_w(fileName));
292 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
293 OPEN_EXISTING, 0, NULL);
294 if (file != INVALID_HANDLE_VALUE)
295 {
296 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
297 CERT_STORE_CREATE_NEW_FLAG, NULL);
298
299 ret = CRYPT_ReadSerializedStoreFromFile(file, store);
300 if (ret)
301 {
302 if (pdwMsgAndCertEncodingType)
303 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
304 if (pdwContentType)
305 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
306 if (phCertStore)
307 *phCertStore = CertDuplicateStore(store);
308 }
309 CertCloseStore(store, 0);
310 CloseHandle(file);
311 }
312 TRACE("returning %d\n", ret);
313 return ret;
314 }
315
316 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
317 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
318 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
319 {
320 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
321 CERT_STORE_CREATE_NEW_FLAG, NULL);
322 BOOL ret;
323
324 TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
325
326 ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
327 if (ret)
328 {
329 if (pdwMsgAndCertEncodingType)
330 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
331 if (pdwContentType)
332 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
333 if (phCertStore)
334 *phCertStore = CertDuplicateStore(store);
335 }
336 CertCloseStore(store, 0);
337 TRACE("returning %d\n", ret);
338 return ret;
339 }
340
341 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
342 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
343 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
344 {
345 switch (dwObjectType)
346 {
347 case CERT_QUERY_OBJECT_FILE:
348 return CRYPT_QuerySerializedStoreFromFile(pvObject,
349 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
350 case CERT_QUERY_OBJECT_BLOB:
351 return CRYPT_QuerySerializedStoreFromBlob(pvObject,
352 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
353 default:
354 FIXME("unimplemented for type %d\n", dwObjectType);
355 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
356 return FALSE;
357 }
358 }
359
360 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
361 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
362 {
363 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
364 BOOL ret = FALSE;
365 HCRYPTMSG msg;
366
367 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
368 {
369 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
370 if (ret)
371 {
372 DWORD type, len = sizeof(type);
373
374 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
375 if (ret)
376 {
377 if (type != CMSG_SIGNED)
378 {
379 SetLastError(ERROR_INVALID_DATA);
380 ret = FALSE;
381 }
382 }
383 }
384 if (!ret)
385 {
386 CryptMsgClose(msg);
387 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
388 NULL);
389 if (msg)
390 {
391 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
392 if (!ret)
393 {
394 CryptMsgClose(msg);
395 msg = NULL;
396 }
397 }
398 }
399 }
400 if (ret)
401 {
402 if (pdwMsgAndCertEncodingType)
403 *pdwMsgAndCertEncodingType = encodingType;
404 if (pdwContentType)
405 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
406 if (phMsg)
407 *phMsg = msg;
408 }
409 return ret;
410 }
411
412 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
413 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
414 {
415 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
416 BOOL ret = FALSE;
417 HCRYPTMSG msg;
418
419 if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
420 {
421 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
422 if (ret)
423 {
424 DWORD type, len = sizeof(type);
425
426 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
427 if (ret)
428 {
429 if (type != CMSG_DATA)
430 {
431 SetLastError(ERROR_INVALID_DATA);
432 ret = FALSE;
433 }
434 }
435 }
436 if (!ret)
437 {
438 CryptMsgClose(msg);
439 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
440 NULL, NULL);
441 if (msg)
442 {
443 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
444 if (!ret)
445 {
446 CryptMsgClose(msg);
447 msg = NULL;
448 }
449 }
450 }
451 }
452 if (ret)
453 {
454 if (pdwMsgAndCertEncodingType)
455 *pdwMsgAndCertEncodingType = encodingType;
456 if (pdwContentType)
457 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
458 if (phMsg)
459 *phMsg = msg;
460 }
461 return ret;
462 }
463
464 /* Used to decode non-embedded messages */
465 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
466 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
467 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
468 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
469 {
470 CERT_BLOB fileBlob;
471 const CERT_BLOB *blob;
472 BOOL ret;
473 HCRYPTMSG msg = NULL;
474 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
475 DWORD formatType = 0;
476
477 TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
478 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
479 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
480 phMsg);
481
482 switch (dwObjectType)
483 {
484 case CERT_QUERY_OBJECT_FILE:
485 /* This isn't an embedded PKCS7 message, so just read the file
486 * directly
487 */
488 ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
489 blob = &fileBlob;
490 break;
491 case CERT_QUERY_OBJECT_BLOB:
492 blob = pvObject;
493 ret = TRUE;
494 break;
495 default:
496 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
497 ret = FALSE;
498 }
499 if (!ret)
500 return FALSE;
501
502 ret = FALSE;
503 if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
504 {
505 /* Try it first as a signed message */
506 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
507 ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
508 pdwContentType, &msg);
509 /* Failing that, try as an unsigned message */
510 if (!ret &&
511 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
512 ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
513 pdwContentType, &msg);
514 if (ret)
515 formatType = CERT_QUERY_FORMAT_BINARY;
516 }
517 if (!ret &&
518 (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
519 {
520 CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
521 CRYPT_DATA_BLOB decoded;
522
523 while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
524 trimmed.cbData--;
525 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
526 CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
527 if (ret)
528 {
529 decoded.pbData = CryptMemAlloc(decoded.cbData);
530 if (decoded.pbData)
531 {
532 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
533 trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
534 &decoded.cbData, NULL, NULL);
535 if (ret)
536 {
537 /* Try it first as a signed message */
538 if (dwExpectedContentTypeFlags &
539 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
540 ret = CRYPT_QuerySignedMessage(&decoded,
541 pdwMsgAndCertEncodingType, pdwContentType, &msg);
542 /* Failing that, try as an unsigned message */
543 if (!ret && (dwExpectedContentTypeFlags &
544 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
545 ret = CRYPT_QueryUnsignedMessage(&decoded,
546 pdwMsgAndCertEncodingType, pdwContentType, &msg);
547 if (ret)
548 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
549 }
550 CryptMemFree(decoded.pbData);
551 }
552 else
553 ret = FALSE;
554 }
555 if (!ret && !(blob->cbData % sizeof(WCHAR)))
556 {
557 CRYPT_DATA_BLOB decoded;
558 LPWSTR str = (LPWSTR)blob->pbData;
559 DWORD strLen = blob->cbData / sizeof(WCHAR);
560
561 /* Try again, assuming the input string is UTF-16 base64 */
562 while (strLen && !str[strLen - 1])
563 strLen--;
564 ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
565 NULL, &decoded.cbData, NULL, NULL);
566 if (ret)
567 {
568 decoded.pbData = CryptMemAlloc(decoded.cbData);
569 if (decoded.pbData)
570 {
571 ret = CryptStringToBinaryW(str, strLen,
572 CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
573 NULL, NULL);
574 if (ret)
575 {
576 /* Try it first as a signed message */
577 if (dwExpectedContentTypeFlags &
578 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
579 ret = CRYPT_QuerySignedMessage(&decoded,
580 pdwMsgAndCertEncodingType, pdwContentType, &msg);
581 /* Failing that, try as an unsigned message */
582 if (!ret && (dwExpectedContentTypeFlags &
583 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
584 ret = CRYPT_QueryUnsignedMessage(&decoded,
585 pdwMsgAndCertEncodingType, pdwContentType, &msg);
586 if (ret)
587 formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
588 }
589 CryptMemFree(decoded.pbData);
590 }
591 else
592 ret = FALSE;
593 }
594 }
595 }
596 if (ret)
597 {
598 if (pdwFormatType)
599 *pdwFormatType = formatType;
600 if (phCertStore)
601 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
602 0, msg);
603 if (phMsg)
604 *phMsg = msg;
605 else
606 CryptMsgClose(msg);
607 }
608 if (blob == &fileBlob)
609 CryptMemFree(blob->pbData);
610 TRACE("returning %d\n", ret);
611 return ret;
612 }
613
614 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
615 const void *pvObject, DWORD dwExpectedContentTypeFlags,
616 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
617 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
618 {
619 HANDLE file;
620 GUID subject;
621 BOOL ret = FALSE;
622
623 TRACE("%s\n", debugstr_w(pvObject));
624
625 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
626 {
627 WARN("don't know what to do for type %d embedded signed messages\n",
628 dwObjectType);
629 SetLastError(E_INVALIDARG);
630 return FALSE;
631 }
632 file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
633 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
634 if (file != INVALID_HANDLE_VALUE)
635 {
636 ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
637 if (ret)
638 {
639 SIP_DISPATCH_INFO sip;
640
641 memset(&sip, 0, sizeof(sip));
642 sip.cbSize = sizeof(sip);
643 ret = CryptSIPLoad(&subject, 0, &sip);
644 if (ret)
645 {
646 SIP_SUBJECTINFO subjectInfo;
647 CERT_BLOB blob;
648 DWORD encodingType;
649
650 memset(&subjectInfo, 0, sizeof(subjectInfo));
651 subjectInfo.cbSize = sizeof(subjectInfo);
652 subjectInfo.pgSubjectType = &subject;
653 subjectInfo.hFile = file;
654 subjectInfo.pwsFileName = pvObject;
655 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
656 NULL);
657 if (ret)
658 {
659 blob.pbData = CryptMemAlloc(blob.cbData);
660 if (blob.pbData)
661 {
662 ret = sip.pfGet(&subjectInfo, &encodingType, 0,
663 &blob.cbData, blob.pbData);
664 if (ret)
665 {
666 ret = CRYPT_QueryMessageObject(
667 CERT_QUERY_OBJECT_BLOB, &blob,
668 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
669 CERT_QUERY_FORMAT_FLAG_BINARY,
670 pdwMsgAndCertEncodingType, NULL, NULL,
671 phCertStore, phMsg);
672 if (ret && pdwContentType)
673 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
674 }
675 CryptMemFree(blob.pbData);
676 }
677 else
678 {
679 SetLastError(ERROR_OUTOFMEMORY);
680 ret = FALSE;
681 }
682 }
683 }
684 }
685 CloseHandle(file);
686 }
687 TRACE("returning %d\n", ret);
688 return ret;
689 }
690
691 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
692 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
693 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
694 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
695 const void **ppvContext)
696 {
697 static const DWORD unimplementedTypes =
698 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
699 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
700 BOOL ret = TRUE;
701
702 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
703 dwObjectType, pvObject, dwExpectedContentTypeFlags,
704 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
705 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
706
707 if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
708 dwObjectType != CERT_QUERY_OBJECT_FILE)
709 {
710 WARN("unsupported type %d\n", dwObjectType);
711 SetLastError(E_INVALIDARG);
712 return FALSE;
713 }
714 if (!pvObject)
715 {
716 WARN("missing required argument\n");
717 SetLastError(E_INVALIDARG);
718 return FALSE;
719 }
720 if (dwExpectedContentTypeFlags & unimplementedTypes)
721 WARN("unimplemented for types %08x\n",
722 dwExpectedContentTypeFlags & unimplementedTypes);
723
724 if (pdwFormatType)
725 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
726 if (phCertStore)
727 *phCertStore = NULL;
728 if (phMsg)
729 *phMsg = NULL;
730 if (ppvContext)
731 *ppvContext = NULL;
732
733 ret = FALSE;
734 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
735 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
736 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
737 {
738 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
739 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
740 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
741 ppvContext);
742 }
743 if (!ret &&
744 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
745 {
746 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
747 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
748 }
749 if (!ret &&
750 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
751 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
752 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
753 {
754 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
755 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
756 phCertStore, ppvContext);
757 }
758 if (!ret &&
759 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
760 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
761 {
762 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
763 dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
764 pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
765 phCertStore, phMsg);
766 }
767 if (!ret &&
768 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
769 {
770 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
771 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
772 phCertStore, phMsg);
773 }
774 if (!ret)
775 SetLastError(CRYPT_E_NO_MATCH);
776 TRACE("returning %d\n", ret);
777 return ret;
778 }
779
780 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
781 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
782 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
783 DWORD *pcbFormat)
784 {
785 BOOL ret;
786 DWORD bytesNeeded;
787
788 if (cbEncoded)
789 bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
790 else
791 bytesNeeded = sizeof(WCHAR);
792 if (!pbFormat)
793 {
794 *pcbFormat = bytesNeeded;
795 ret = TRUE;
796 }
797 else if (*pcbFormat < bytesNeeded)
798 {
799 *pcbFormat = bytesNeeded;
800 SetLastError(ERROR_MORE_DATA);
801 ret = FALSE;
802 }
803 else
804 {
805 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
806 static const WCHAR endFmt[] = { '%','0','2','x',0 };
807 DWORD i;
808 LPWSTR ptr = pbFormat;
809
810 *pcbFormat = bytesNeeded;
811 if (cbEncoded)
812 {
813 for (i = 0; i < cbEncoded; i++)
814 {
815 if (i < cbEncoded - 1)
816 ptr += sprintfW(ptr, fmt, pbEncoded[i]);
817 else
818 ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
819 }
820 }
821 else
822 *ptr = 0;
823 ret = TRUE;
824 }
825 return ret;
826 }
827
828 #define MAX_STRING_RESOURCE_LEN 128
829
830 static const WCHAR commaSpace[] = { ',',' ',0 };
831
832 struct BitToString
833 {
834 BYTE bit;
835 int id;
836 WCHAR str[MAX_STRING_RESOURCE_LEN];
837 };
838
839 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
840 DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
841 {
842 DWORD bytesNeeded = sizeof(WCHAR);
843 unsigned int i;
844 BOOL ret = TRUE, localFirst = *first;
845
846 for (i = 0; i < mapEntries; i++)
847 if (bits & map[i].bit)
848 {
849 if (!localFirst)
850 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
851 localFirst = FALSE;
852 bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
853 }
854 if (!pbFormat)
855 {
856 *first = localFirst;
857 *pcbFormat = bytesNeeded;
858 }
859 else if (*pcbFormat < bytesNeeded)
860 {
861 *first = localFirst;
862 *pcbFormat = bytesNeeded;
863 SetLastError(ERROR_MORE_DATA);
864 ret = FALSE;
865 }
866 else
867 {
868 LPWSTR str = pbFormat;
869
870 localFirst = *first;
871 *pcbFormat = bytesNeeded;
872 for (i = 0; i < mapEntries; i++)
873 if (bits & map[i].bit)
874 {
875 if (!localFirst)
876 {
877 strcpyW(str, commaSpace);
878 str += strlenW(commaSpace);
879 }
880 localFirst = FALSE;
881 strcpyW(str, map[i].str);
882 str += strlenW(map[i].str);
883 }
884 *first = localFirst;
885 }
886 return ret;
887 }
888
889 static struct BitToString keyUsageByte0Map[] = {
890 { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
891 { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
892 { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
893 { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
894 { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
895 { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
896 { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
897 { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
898 { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
899 };
900 static struct BitToString keyUsageByte1Map[] = {
901 { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
902 };
903
904 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
905 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
906 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
907 DWORD *pcbFormat)
908 {
909 DWORD size;
910 CRYPT_BIT_BLOB *bits;
911 BOOL ret;
912
913 if (!cbEncoded)
914 {
915 SetLastError(E_INVALIDARG);
916 return FALSE;
917 }
918 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
919 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
920 {
921 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
922 DWORD bytesNeeded = sizeof(WCHAR);
923
924 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
925 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
926 if (!bits->cbData || bits->cbData > 2)
927 {
928 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
929 if (!pbFormat)
930 *pcbFormat = bytesNeeded;
931 else if (*pcbFormat < bytesNeeded)
932 {
933 *pcbFormat = bytesNeeded;
934 SetLastError(ERROR_MORE_DATA);
935 ret = FALSE;
936 }
937 else
938 {
939 LPWSTR str = pbFormat;
940
941 *pcbFormat = bytesNeeded;
942 strcpyW(str, infoNotAvailable);
943 }
944 }
945 else
946 {
947 static BOOL stringsLoaded = FALSE;
948 unsigned int i;
949 DWORD bitStringLen;
950 BOOL first = TRUE;
951
952 if (!stringsLoaded)
953 {
954 for (i = 0;
955 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
956 i++)
957 LoadStringW(hInstance, keyUsageByte0Map[i].id,
958 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
959 for (i = 0;
960 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
961 i++)
962 LoadStringW(hInstance, keyUsageByte1Map[i].id,
963 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
964 stringsLoaded = TRUE;
965 }
966 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
967 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
968 NULL, &bitStringLen, &first);
969 bytesNeeded += bitStringLen;
970 if (bits->cbData == 2)
971 {
972 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
973 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
974 NULL, &bitStringLen, &first);
975 bytesNeeded += bitStringLen;
976 }
977 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
978 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
979 bits->cbData, NULL, &size);
980 bytesNeeded += size;
981 if (!pbFormat)
982 *pcbFormat = bytesNeeded;
983 else if (*pcbFormat < bytesNeeded)
984 {
985 *pcbFormat = bytesNeeded;
986 SetLastError(ERROR_MORE_DATA);
987 ret = FALSE;
988 }
989 else
990 {
991 LPWSTR str = pbFormat;
992
993 bitStringLen = bytesNeeded;
994 first = TRUE;
995 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
996 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
997 str, &bitStringLen, &first);
998 str += bitStringLen / sizeof(WCHAR) - 1;
999 if (bits->cbData == 2)
1000 {
1001 bitStringLen = bytesNeeded;
1002 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
1003 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
1004 str, &bitStringLen, &first);
1005 str += bitStringLen / sizeof(WCHAR) - 1;
1006 }
1007 *str++ = ' ';
1008 *str++ = '(';
1009 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
1010 bits->cbData, str, &size);
1011 str += size / sizeof(WCHAR) - 1;
1012 *str++ = ')';
1013 *str = 0;
1014 }
1015 }
1016 LocalFree(bits);
1017 }
1018 return ret;
1019 }
1020
1021 static const WCHAR crlf[] = { '\r','\n',0 };
1022
1023 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
1024 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
1025 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
1026 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
1027
1028 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
1029 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1030 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1031 DWORD *pcbFormat)
1032 {
1033 DWORD size;
1034 CERT_BASIC_CONSTRAINTS2_INFO *info;
1035 BOOL ret;
1036
1037 if (!cbEncoded)
1038 {
1039 SetLastError(E_INVALIDARG);
1040 return FALSE;
1041 }
1042 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
1043 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1044 {
1045 static const WCHAR pathFmt[] = { '%','d',0 };
1046 static BOOL stringsLoaded = FALSE;
1047 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1048 WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
1049 LPCWSTR sep, subjectType;
1050 DWORD sepLen;
1051
1052 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1053 {
1054 sep = crlf;
1055 sepLen = strlenW(crlf) * sizeof(WCHAR);
1056 }
1057 else
1058 {
1059 sep = commaSpace;
1060 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1061 }
1062
1063 if (!stringsLoaded)
1064 {
1065 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
1066 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
1067 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
1068 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
1069 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
1070 subjectTypeEndCert,
1071 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
1072 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
1073 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
1074 stringsLoaded = TRUE;
1075 }
1076 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
1077 if (info->fCA)
1078 subjectType = subjectTypeCA;
1079 else
1080 subjectType = subjectTypeEndCert;
1081 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
1082 bytesNeeded += sepLen;
1083 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
1084 if (info->fPathLenConstraint)
1085 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
1086 else
1087 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
1088 sizeof(pathLength) / sizeof(pathLength[0]));
1089 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
1090 if (!pbFormat)
1091 *pcbFormat = bytesNeeded;
1092 else if (*pcbFormat < bytesNeeded)
1093 {
1094 *pcbFormat = bytesNeeded;
1095 SetLastError(ERROR_MORE_DATA);
1096 ret = FALSE;
1097 }
1098 else
1099 {
1100 LPWSTR str = pbFormat;
1101
1102 *pcbFormat = bytesNeeded;
1103 strcpyW(str, subjectTypeHeader);
1104 str += strlenW(subjectTypeHeader);
1105 strcpyW(str, subjectType);
1106 str += strlenW(subjectType);
1107 strcpyW(str, sep);
1108 str += sepLen / sizeof(WCHAR);
1109 strcpyW(str, pathLengthHeader);
1110 str += strlenW(pathLengthHeader);
1111 strcpyW(str, pathLength);
1112 }
1113 LocalFree(info);
1114 }
1115 return ret;
1116 }
1117
1118 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
1119 LPWSTR str, DWORD *pcbStr)
1120 {
1121 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1122 DWORD bytesNeeded;
1123 BOOL ret;
1124
1125 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
1126 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1127 blob->pbData, blob->cbData, NULL, &bytesNeeded);
1128 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1129 if (!str)
1130 {
1131 *pcbStr = bytesNeeded;
1132 ret = TRUE;
1133 }
1134 else if (*pcbStr < bytesNeeded)
1135 {
1136 *pcbStr = bytesNeeded;
1137 SetLastError(ERROR_MORE_DATA);
1138 ret = FALSE;
1139 }
1140 else
1141 {
1142 *pcbStr = bytesNeeded;
1143 strcpyW(str, buf);
1144 str += strlenW(str);
1145 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1146 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
1147 blob->pbData, blob->cbData, str, &bytesNeeded);
1148 }
1149 return ret;
1150 }
1151
1152 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
1153 DWORD *pcbStr)
1154 {
1155 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
1156 }
1157
1158 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
1159 DWORD *pcbStr)
1160 {
1161 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
1162 str, pcbStr);
1163 }
1164
1165 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
1166 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
1167
1168 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
1169 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
1170 {
1171 BOOL ret;
1172 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1173 WCHAR mask[MAX_STRING_RESOURCE_LEN];
1174 WCHAR ipAddrBuf[32];
1175 WCHAR maskBuf[16];
1176 DWORD bytesNeeded = sizeof(WCHAR);
1177 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
1178
1179 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1180 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1181 switch (entry->dwAltNameChoice)
1182 {
1183 case CERT_ALT_NAME_RFC822_NAME:
1184 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
1185 sizeof(buf) / sizeof(buf[0]));
1186 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
1187 ret = TRUE;
1188 break;
1189 case CERT_ALT_NAME_DNS_NAME:
1190 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
1191 sizeof(buf) / sizeof(buf[0]));
1192 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
1193 ret = TRUE;
1194 break;
1195 case CERT_ALT_NAME_DIRECTORY_NAME:
1196 {
1197 DWORD directoryNameLen;
1198
1199 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1200 strType |= CERT_NAME_STR_CRLF_FLAG;
1201 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
1202 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
1203 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
1204 sizeof(buf) / sizeof(buf[0]));
1205 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
1206 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1207 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
1208 else
1209 bytesNeeded += sizeof(WCHAR); /* '=' */
1210 ret = TRUE;
1211 break;
1212 }
1213 case CERT_ALT_NAME_URL:
1214 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
1215 sizeof(buf) / sizeof(buf[0]));
1216 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
1217 ret = TRUE;
1218 break;
1219 case CERT_ALT_NAME_IP_ADDRESS:
1220 {
1221 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
1222 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
1223 };
1224 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
1225 '.','%','d',0 };
1226
1227 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
1228 sizeof(buf) / sizeof(buf[0]));
1229 if (entry->u.IPAddress.cbData == 8)
1230 {
1231 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1232 {
1233 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
1234 sizeof(mask) / sizeof(mask[0]));
1235 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
1236 sprintfW(ipAddrBuf, ipAddrFmt,
1237 entry->u.IPAddress.pbData[0],
1238 entry->u.IPAddress.pbData[1],
1239 entry->u.IPAddress.pbData[2],
1240 entry->u.IPAddress.pbData[3]);
1241 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
1242 /* indent again, for the mask line */
1243 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
1244 sprintfW(maskBuf, ipAddrFmt,
1245 entry->u.IPAddress.pbData[4],
1246 entry->u.IPAddress.pbData[5],
1247 entry->u.IPAddress.pbData[6],
1248 entry->u.IPAddress.pbData[7]);
1249 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
1250 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
1251 }
1252 else
1253 {
1254 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
1255 entry->u.IPAddress.pbData[0],
1256 entry->u.IPAddress.pbData[1],
1257 entry->u.IPAddress.pbData[2],
1258 entry->u.IPAddress.pbData[3],
1259 entry->u.IPAddress.pbData[4],
1260 entry->u.IPAddress.pbData[5],
1261 entry->u.IPAddress.pbData[6],
1262 entry->u.IPAddress.pbData[7]);
1263 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
1264 }
1265 ret = TRUE;
1266 }
1267 else
1268 {
1269 FIXME("unknown IP address format (%d bytes)\n",
1270 entry->u.IPAddress.cbData);
1271 ret = FALSE;
1272 }
1273 break;
1274 }
1275 default:
1276 FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
1277 ret = FALSE;
1278 }
1279 if (ret)
1280 {
1281 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1282 if (!str)
1283 *pcbStr = bytesNeeded;
1284 else if (*pcbStr < bytesNeeded)
1285 {
1286 *pcbStr = bytesNeeded;
1287 SetLastError(ERROR_MORE_DATA);
1288 ret = FALSE;
1289 }
1290 else
1291 {
1292 DWORD i;
1293
1294 *pcbStr = bytesNeeded;
1295 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1296 {
1297 for (i = 0; i < indentLevel; i++)
1298 {
1299 strcpyW(str, indent);
1300 str += strlenW(indent);
1301 }
1302 }
1303 strcpyW(str, buf);
1304 str += strlenW(str);
1305 switch (entry->dwAltNameChoice)
1306 {
1307 case CERT_ALT_NAME_RFC822_NAME:
1308 case CERT_ALT_NAME_DNS_NAME:
1309 case CERT_ALT_NAME_URL:
1310 strcpyW(str, entry->u.pwszURL);
1311 break;
1312 case CERT_ALT_NAME_DIRECTORY_NAME:
1313 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1314 {
1315 strcpyW(str, colonCrlf);
1316 str += strlenW(colonCrlf);
1317 }
1318 else
1319 *str++ = '=';
1320 cert_name_to_str_with_indent(X509_ASN_ENCODING,
1321 indentLevel + 1, &entry->u.DirectoryName, strType, str,
1322 bytesNeeded / sizeof(WCHAR));
1323 break;
1324 case CERT_ALT_NAME_IP_ADDRESS:
1325 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1326 {
1327 strcpyW(str, ipAddrBuf);
1328 str += strlenW(ipAddrBuf);
1329 strcpyW(str, crlf);
1330 str += strlenW(crlf);
1331 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1332 {
1333 for (i = 0; i < indentLevel; i++)
1334 {
1335 strcpyW(str, indent);
1336 str += strlenW(indent);
1337 }
1338 }
1339 strcpyW(str, mask);
1340 str += strlenW(mask);
1341 strcpyW(str, maskBuf);
1342 }
1343 else
1344 strcpyW(str, ipAddrBuf);
1345 break;
1346 }
1347 }
1348 }
1349 return ret;
1350 }
1351
1352 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
1353 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
1354 {
1355 DWORD i, size, bytesNeeded = 0;
1356 BOOL ret = TRUE;
1357 LPCWSTR sep;
1358 DWORD sepLen;
1359
1360 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1361 {
1362 sep = crlf;
1363 sepLen = strlenW(crlf) * sizeof(WCHAR);
1364 }
1365 else
1366 {
1367 sep = commaSpace;
1368 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1369 }
1370
1371 for (i = 0; ret && i < name->cAltEntry; i++)
1372 {
1373 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1374 &name->rgAltEntry[i], NULL, &size);
1375 if (ret)
1376 {
1377 bytesNeeded += size - sizeof(WCHAR);
1378 if (i < name->cAltEntry - 1)
1379 bytesNeeded += sepLen;
1380 }
1381 }
1382 if (ret)
1383 {
1384 bytesNeeded += sizeof(WCHAR);
1385 if (!str)
1386 *pcbStr = bytesNeeded;
1387 else if (*pcbStr < bytesNeeded)
1388 {
1389 *pcbStr = bytesNeeded;
1390 SetLastError(ERROR_MORE_DATA);
1391 ret = FALSE;
1392 }
1393 else
1394 {
1395 *pcbStr = bytesNeeded;
1396 for (i = 0; ret && i < name->cAltEntry; i++)
1397 {
1398 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
1399 &name->rgAltEntry[i], str, &size);
1400 if (ret)
1401 {
1402 str += size / sizeof(WCHAR) - 1;
1403 if (i < name->cAltEntry - 1)
1404 {
1405 strcpyW(str, sep);
1406 str += sepLen / sizeof(WCHAR);
1407 }
1408 }
1409 }
1410 }
1411 }
1412 return ret;
1413 }
1414
1415 static const WCHAR colonSep[] = { ':',' ',0 };
1416
1417 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
1418 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1419 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1420 DWORD *pcbFormat)
1421 {
1422 BOOL ret;
1423 CERT_ALT_NAME_INFO *info;
1424 DWORD size;
1425
1426 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
1427 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1428 {
1429 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
1430 LocalFree(info);
1431 }
1432 return ret;
1433 }
1434
1435 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
1436 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
1437 {
1438 WCHAR buf[MAX_STRING_RESOURCE_LEN];
1439 DWORD bytesNeeded, sepLen;
1440 LPCWSTR sep;
1441 BOOL ret;
1442
1443 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
1444 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
1445 &bytesNeeded);
1446 bytesNeeded += strlenW(buf) * sizeof(WCHAR);
1447 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1448 {
1449 sep = colonCrlf;
1450 sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
1451 }
1452 else
1453 {
1454 sep = colonSep;
1455 sepLen = strlenW(colonSep) * sizeof(WCHAR);
1456 }
1457 bytesNeeded += sepLen;
1458 if (ret)
1459 {
1460 if (!str)
1461 *pcbStr = bytesNeeded;
1462 else if (*pcbStr < bytesNeeded)
1463 {
1464 *pcbStr = bytesNeeded;
1465 SetLastError(ERROR_MORE_DATA);
1466 ret = FALSE;
1467 }
1468 else
1469 {
1470 *pcbStr = bytesNeeded;
1471 strcpyW(str, buf);
1472 bytesNeeded -= strlenW(str) * sizeof(WCHAR);
1473 str += strlenW(str);
1474 strcpyW(str, sep);
1475 str += sepLen / sizeof(WCHAR);
1476 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
1477 &bytesNeeded);
1478 }
1479 }
1480 return ret;
1481 }
1482
1483 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
1484 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1485 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1486 DWORD *pcbFormat)
1487 {
1488 CERT_AUTHORITY_KEY_ID2_INFO *info;
1489 DWORD size;
1490 BOOL ret = FALSE;
1491
1492 if (!cbEncoded)
1493 {
1494 SetLastError(E_INVALIDARG);
1495 return FALSE;
1496 }
1497 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
1498 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1499 {
1500 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
1501 LPCWSTR sep;
1502 DWORD sepLen;
1503 BOOL needSeparator = FALSE;
1504
1505 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1506 {
1507 sep = crlf;
1508 sepLen = strlenW(crlf) * sizeof(WCHAR);
1509 }
1510 else
1511 {
1512 sep = commaSpace;
1513 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
1514 }
1515
1516 if (info->KeyId.cbData)
1517 {
1518 needSeparator = TRUE;
1519 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
1520 if (ret)
1521 {
1522 /* don't include NULL-terminator more than once */
1523 bytesNeeded += size - sizeof(WCHAR);
1524 }
1525 }
1526 if (info->AuthorityCertIssuer.cAltEntry)
1527 {
1528 if (needSeparator)
1529 bytesNeeded += sepLen;
1530 needSeparator = TRUE;
1531 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1532 &info->AuthorityCertIssuer, NULL, &size);
1533 if (ret)
1534 {
1535 /* don't include NULL-terminator more than once */
1536 bytesNeeded += size - sizeof(WCHAR);
1537 }
1538 }
1539 if (info->AuthorityCertSerialNumber.cbData)
1540 {
1541 if (needSeparator)
1542 bytesNeeded += sepLen;
1543 ret = CRYPT_FormatCertSerialNumber(
1544 &info->AuthorityCertSerialNumber, NULL, &size);
1545 if (ret)
1546 {
1547 /* don't include NULL-terminator more than once */
1548 bytesNeeded += size - sizeof(WCHAR);
1549 }
1550 }
1551 if (ret)
1552 {
1553 if (!pbFormat)
1554 *pcbFormat = bytesNeeded;
1555 else if (*pcbFormat < bytesNeeded)
1556 {
1557 *pcbFormat = bytesNeeded;
1558 SetLastError(ERROR_MORE_DATA);
1559 ret = FALSE;
1560 }
1561 else
1562 {
1563 LPWSTR str = pbFormat;
1564
1565 *pcbFormat = bytesNeeded;
1566 needSeparator = FALSE;
1567 if (info->KeyId.cbData)
1568 {
1569 needSeparator = TRUE;
1570 /* Overestimate size available, it's already been checked
1571 * above.
1572 */
1573 size = bytesNeeded;
1574 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
1575 if (ret)
1576 str += size / sizeof(WCHAR) - 1;
1577 }
1578 if (info->AuthorityCertIssuer.cAltEntry)
1579 {
1580 if (needSeparator)
1581 {
1582 strcpyW(str, sep);
1583 str += sepLen / sizeof(WCHAR);
1584 }
1585 needSeparator = TRUE;
1586 /* Overestimate size available, it's already been checked
1587 * above.
1588 */
1589 size = bytesNeeded;
1590 ret = CRYPT_FormatCertIssuer(dwFormatStrType,
1591 &info->AuthorityCertIssuer, str, &size);
1592 if (ret)
1593 str += size / sizeof(WCHAR) - 1;
1594 }
1595 if (info->AuthorityCertSerialNumber.cbData)
1596 {
1597 if (needSeparator)
1598 {
1599 strcpyW(str, sep);
1600 str += sepLen / sizeof(WCHAR);
1601 }
1602 /* Overestimate size available, it's already been checked
1603 * above.
1604 */
1605 size = bytesNeeded;
1606 ret = CRYPT_FormatCertSerialNumber(
1607 &info->AuthorityCertSerialNumber, str, &size);
1608 }
1609 }
1610 }
1611 LocalFree(info);
1612 }
1613 return ret;
1614 }
1615
1616 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
1617 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
1618 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
1619 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
1620 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
1621 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
1622
1623 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
1624 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1625 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1626 DWORD *pcbFormat)
1627 {
1628 CERT_AUTHORITY_INFO_ACCESS *info;
1629 DWORD size;
1630 BOOL ret = FALSE;
1631
1632 if (!cbEncoded)
1633 {
1634 SetLastError(E_INVALIDARG);
1635 return FALSE;
1636 }
1637 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
1638 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
1639 NULL, &info, &size)))
1640 {
1641 DWORD bytesNeeded = sizeof(WCHAR);
1642
1643 if (!info->cAccDescr)
1644 {
1645 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
1646
1647 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
1648 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
1649 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
1650 if (!pbFormat)
1651 *pcbFormat = bytesNeeded;
1652 else if (*pcbFormat < bytesNeeded)
1653 {
1654 *pcbFormat = bytesNeeded;
1655 SetLastError(ERROR_MORE_DATA);
1656 ret = FALSE;
1657 }
1658 else
1659 {
1660 *pcbFormat = bytesNeeded;
1661 strcpyW(pbFormat, infoNotAvailable);
1662 }
1663 }
1664 else
1665 {
1666 static const WCHAR numFmt[] = { '%','d',0 };
1667 static const WCHAR equal[] = { '=',0 };
1668 static BOOL stringsLoaded = FALSE;
1669 DWORD i;
1670 LPCWSTR headingSep, accessMethodSep, locationSep;
1671 WCHAR accessDescrNum[11];
1672
1673 if (!stringsLoaded)
1674 {
1675 LoadStringW(hInstance, IDS_AIA, aia,
1676 sizeof(aia) / sizeof(aia[0]));
1677 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
1678 sizeof(accessMethod) / sizeof(accessMethod[0]));
1679 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
1680 sizeof(ocsp) / sizeof(ocsp[0]));
1681 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
1682 sizeof(caIssuers) / sizeof(caIssuers[0]));
1683 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
1684 sizeof(unknown) / sizeof(unknown[0]));
1685 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
1686 sizeof(accessLocation) / sizeof(accessLocation[0]));
1687 stringsLoaded = TRUE;
1688 }
1689 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1690 {
1691 headingSep = crlf;
1692 accessMethodSep = crlf;
1693 locationSep = colonCrlf;
1694 }
1695 else
1696 {
1697 headingSep = colonSep;
1698 accessMethodSep = commaSpace;
1699 locationSep = equal;
1700 }
1701
1702 for (i = 0; ret && i < info->cAccDescr; i++)
1703 {
1704 /* Heading */
1705 bytesNeeded += sizeof(WCHAR); /* left bracket */
1706 sprintfW(accessDescrNum, numFmt, i + 1);
1707 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
1708 bytesNeeded += sizeof(WCHAR); /* right bracket */
1709 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
1710 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
1711 /* Access method */
1712 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
1713 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1714 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1715 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1716 szOID_PKIX_OCSP))
1717 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
1718 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1719 szOID_PKIX_CA_ISSUERS))
1720 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
1721 else
1722 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
1723 bytesNeeded += sizeof(WCHAR); /* space */
1724 bytesNeeded += sizeof(WCHAR); /* left paren */
1725 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
1726 * sizeof(WCHAR);
1727 bytesNeeded += sizeof(WCHAR); /* right paren */
1728 /* Delimiter between access method and location */
1729 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1730 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1731 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
1732 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
1733 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
1734 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1735 &info->rgAccDescr[i].AccessLocation, NULL, &size);
1736 if (ret)
1737 bytesNeeded += size - sizeof(WCHAR);
1738 /* Need extra delimiter between access method entries */
1739 if (i < info->cAccDescr - 1)
1740 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
1741 }
1742 if (ret)
1743 {
1744 if (!pbFormat)
1745 *pcbFormat = bytesNeeded;
1746 else if (*pcbFormat < bytesNeeded)
1747 {
1748 *pcbFormat = bytesNeeded;
1749 SetLastError(ERROR_MORE_DATA);
1750 ret = FALSE;
1751 }
1752 else
1753 {
1754 LPWSTR str = pbFormat;
1755 DWORD altNameEntrySize;
1756
1757 *pcbFormat = bytesNeeded;
1758 for (i = 0; ret && i < info->cAccDescr; i++)
1759 {
1760 LPCSTR oidPtr;
1761
1762 *str++ = '[';
1763 sprintfW(accessDescrNum, numFmt, i + 1);
1764 strcpyW(str, accessDescrNum);
1765 str += strlenW(accessDescrNum);
1766 *str++ = ']';
1767 strcpyW(str, aia);
1768 str += strlenW(aia);
1769 strcpyW(str, headingSep);
1770 str += strlenW(headingSep);
1771 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1772 {
1773 strcpyW(str, indent);
1774 str += strlenW(indent);
1775 }
1776 strcpyW(str, accessMethod);
1777 str += strlenW(accessMethod);
1778 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1779 szOID_PKIX_OCSP))
1780 {
1781 strcpyW(str, ocsp);
1782 str += strlenW(ocsp);
1783 }
1784 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
1785 szOID_PKIX_CA_ISSUERS))
1786 {
1787 strcpyW(str, caIssuers);
1788 str += strlenW(caIssuers);
1789 }
1790 else
1791 {
1792 strcpyW(str, unknown);
1793 str += strlenW(unknown);
1794 }
1795 *str++ = ' ';
1796 *str++ = '(';
1797 for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
1798 *oidPtr; oidPtr++, str++)
1799 *str = *oidPtr;
1800 *str++ = ')';
1801 strcpyW(str, accessMethodSep);
1802 str += strlenW(accessMethodSep);
1803 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1804 {
1805 strcpyW(str, indent);
1806 str += strlenW(indent);
1807 }
1808 strcpyW(str, accessLocation);
1809 str += strlenW(accessLocation);
1810 strcpyW(str, locationSep);
1811 str += strlenW(locationSep);
1812 /* This overestimates the size available, but that
1813 * won't matter since we checked earlier whether enough
1814 * space for the entire string was available.
1815 */
1816 altNameEntrySize = bytesNeeded;
1817 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
1818 &info->rgAccDescr[i].AccessLocation, str,
1819 &altNameEntrySize);
1820 if (ret)
1821 str += altNameEntrySize / sizeof(WCHAR) - 1;
1822 if (i < info->cAccDescr - 1)
1823 {
1824 strcpyW(str, accessMethodSep);
1825 str += strlenW(accessMethodSep);
1826 }
1827 }
1828 }
1829 }
1830 }
1831 LocalFree(info);
1832 }
1833 return ret;
1834 }
1835
1836 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
1837 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
1838 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
1839 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
1840 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
1841 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
1842
1843 struct reason_map_entry
1844 {
1845 BYTE reasonBit;
1846 LPWSTR reason;
1847 int id;
1848 };
1849 static struct reason_map_entry reason_map[] = {
1850 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
1851 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
1852 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
1853 IDS_REASON_AFFILIATION_CHANGED },
1854 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
1855 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
1856 IDS_REASON_CESSATION_OF_OPERATION },
1857 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
1858 IDS_REASON_CERTIFICATE_HOLD },
1859 };
1860
1861 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
1862 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
1863 {
1864 static const WCHAR sep[] = { ',',' ',0 };
1865 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
1866 static BOOL stringsLoaded = FALSE;
1867 unsigned int i, numReasons = 0;
1868 BOOL ret = TRUE;
1869 DWORD bytesNeeded = sizeof(WCHAR);
1870 WCHAR bits[6];
1871
1872 if (!stringsLoaded)
1873 {
1874 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1875 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
1876 MAX_STRING_RESOURCE_LEN);
1877 stringsLoaded = TRUE;
1878 }
1879 /* No need to check reasonFlags->cbData, we already know it's positive.
1880 * Ignore any other bytes, as they're for undefined bits.
1881 */
1882 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1883 {
1884 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1885 {
1886 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
1887 if (numReasons++)
1888 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
1889 }
1890 }
1891 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
1892 bytesNeeded += strlenW(bits);
1893 if (!str)
1894 *pcbStr = bytesNeeded;
1895 else if (*pcbStr < bytesNeeded)
1896 {
1897 *pcbStr = bytesNeeded;
1898 SetLastError(ERROR_MORE_DATA);
1899 ret = FALSE;
1900 }
1901 else
1902 {
1903 *pcbStr = bytesNeeded;
1904 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
1905 {
1906 if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
1907 {
1908 strcpyW(str, reason_map[i].reason);
1909 str += strlenW(reason_map[i].reason);
1910 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
1911 numReasons)
1912 {
1913 strcpyW(str, sep);
1914 str += strlenW(sep);
1915 }
1916 }
1917 }
1918 strcpyW(str, bits);
1919 }
1920 return ret;
1921 }
1922
1923 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
1924 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
1925 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
1926 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
1927 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
1928 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
1929
1930 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
1931 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
1932 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
1933 DWORD *pcbFormat)
1934 {
1935 CRL_DIST_POINTS_INFO *info;
1936 DWORD size;
1937 BOOL ret = FALSE;
1938
1939 if (!cbEncoded)
1940 {
1941 SetLastError(E_INVALIDARG);
1942 return FALSE;
1943 }
1944 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
1945 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
1946 {
1947 static const WCHAR numFmt[] = { '%','d',0 };
1948 static const WCHAR colon[] = { ':',0 };
1949 static BOOL stringsLoaded = FALSE;
1950 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
1951 BOOL haveAnEntry = FALSE;
1952 LPCWSTR headingSep, nameSep;
1953 WCHAR distPointNum[11];
1954 DWORD i;
1955
1956 if (!stringsLoaded)
1957 {
1958 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
1959 sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
1960 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
1961 sizeof(distPointName) / sizeof(distPointName[0]));
1962 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
1963 sizeof(fullName) / sizeof(fullName[0]));
1964 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
1965 sizeof(rdnName) / sizeof(rdnName[0]));
1966 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
1967 sizeof(reason) / sizeof(reason[0]));
1968 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
1969 sizeof(issuer) / sizeof(issuer[0]));
1970 stringsLoaded = TRUE;
1971 }
1972 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1973 {
1974 headingSep = crlf;
1975 nameSep = colonCrlf;
1976 }
1977 else
1978 {
1979 headingSep = colonSep;
1980 nameSep = colon;
1981 }
1982
1983 for (i = 0; ret && i < info->cDistPoint; i++)
1984 {
1985 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
1986
1987 if (distPoint->DistPointName.dwDistPointNameChoice !=
1988 CRL_DIST_POINT_NO_NAME)
1989 {
1990 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
1991 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1992 if (distPoint->DistPointName.dwDistPointNameChoice ==
1993 CRL_DIST_POINT_FULL_NAME)
1994 bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
1995 else
1996 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
1997 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
1998 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
1999 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
2000 /* The indent level (3) is higher than when used as the issuer,
2001 * because the name is subordinate to the name type (full vs.
2002 * RDN.)
2003 */
2004 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2005 &distPoint->DistPointName.u.FullName, NULL, &size);
2006 if (ret)
2007 bytesNeeded += size - sizeof(WCHAR);
2008 haveAnEntry = TRUE;
2009 }
2010 else if (distPoint->ReasonFlags.cbData)
2011 {
2012 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
2013 ret = CRYPT_FormatReason(dwFormatStrType,
2014 &distPoint->ReasonFlags, NULL, &size);
2015 if (ret)
2016 bytesNeeded += size - sizeof(WCHAR);
2017 haveAnEntry = TRUE;
2018 }
2019 else if (distPoint->CRLIssuer.cAltEntry)
2020 {
2021 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
2022 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
2023 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2024 &distPoint->CRLIssuer, NULL, &size);
2025 if (ret)
2026 bytesNeeded += size - sizeof(WCHAR);
2027 haveAnEntry = TRUE;
2028 }
2029 if (haveAnEntry)
2030 {
2031 bytesNeeded += sizeof(WCHAR); /* left bracket */
2032 sprintfW(distPointNum, numFmt, i + 1);
2033 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
2034 bytesNeeded += sizeof(WCHAR); /* right bracket */
2035 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
2036 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
2037 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2038 bytesNeeded += strlenW(indent) * sizeof(WCHAR);
2039 }
2040 }
2041 if (!haveAnEntry)
2042 {
2043 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2044
2045 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2046 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2047 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2048 if (!pbFormat)
2049 *pcbFormat = bytesNeeded;
2050 else if (*pcbFormat < bytesNeeded)
2051 {
2052 *pcbFormat = bytesNeeded;
2053 SetLastError(ERROR_MORE_DATA);
2054 ret = FALSE;
2055 }
2056 else
2057 {
2058 *pcbFormat = bytesNeeded;
2059 strcpyW(pbFormat, infoNotAvailable);
2060 }
2061 }
2062 else
2063 {
2064 if (!pbFormat)
2065 *pcbFormat = bytesNeeded;
2066 else if (*pcbFormat < bytesNeeded)
2067 {
2068 *pcbFormat = bytesNeeded;
2069 SetLastError(ERROR_MORE_DATA);
2070 ret = FALSE;
2071 }
2072 else
2073 {
2074 LPWSTR str = pbFormat;
2075
2076 *pcbFormat = bytesNeeded;
2077 for (i = 0; ret && i < info->cDistPoint; i++)
2078 {
2079 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
2080
2081 *str++ = '[';
2082 sprintfW(distPointNum, numFmt, i + 1);
2083 strcpyW(str, distPointNum);
2084 str += strlenW(distPointNum);
2085 *str++ = ']';
2086 strcpyW(str, crlDistPoint);
2087 str += strlenW(crlDistPoint);
2088 strcpyW(str, headingSep);
2089 str += strlenW(headingSep);
2090 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2091 {
2092 strcpyW(str, indent);
2093 str += strlenW(indent);
2094 }
2095 if (distPoint->DistPointName.dwDistPointNameChoice !=
2096 CRL_DIST_POINT_NO_NAME)
2097 {
2098 DWORD altNameSize = bytesNeeded;
2099
2100 strcpyW(str, distPointName);
2101 str += strlenW(distPointName);
2102 strcpyW(str, nameSep);
2103 str += strlenW(nameSep);
2104 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2105 {
2106 strcpyW(str, indent);
2107 str += strlenW(indent);
2108 strcpyW(str, indent);
2109 str += strlenW(indent);
2110 }
2111 if (distPoint->DistPointName.dwDistPointNameChoice ==
2112 CRL_DIST_POINT_FULL_NAME)
2113 {
2114 strcpyW(str, fullName);
2115 str += strlenW(fullName);
2116 }
2117 else
2118 {
2119 strcpyW(str, rdnName);
2120 str += strlenW(rdnName);
2121 }
2122 strcpyW(str, nameSep);
2123 str += strlenW(nameSep);
2124 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
2125 &distPoint->DistPointName.u.FullName, str,
2126 &altNameSize);
2127 if (ret)
2128 str += altNameSize / sizeof(WCHAR) - 1;
2129 }
2130 else if (distPoint->ReasonFlags.cbData)
2131 {
2132 DWORD reasonSize = bytesNeeded;
2133
2134 strcpyW(str, reason);
2135 str += strlenW(reason);
2136 ret = CRYPT_FormatReason(dwFormatStrType,
2137 &distPoint->ReasonFlags, str, &reasonSize);
2138 if (ret)
2139 str += reasonSize / sizeof(WCHAR) - 1;
2140 }
2141 else if (distPoint->CRLIssuer.cAltEntry)
2142 {
2143 DWORD crlIssuerSize = bytesNeeded;
2144
2145 strcpyW(str, issuer);
2146 str += strlenW(issuer);
2147 strcpyW(str, nameSep);
2148 str += strlenW(nameSep);
2149 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
2150 &distPoint->CRLIssuer, str,
2151 &crlIssuerSize);
2152 if (ret)
2153 str += crlIssuerSize / sizeof(WCHAR) - 1;
2154 }
2155 }
2156 }
2157 }
2158 LocalFree(info);
2159 }
2160 return ret;
2161 }
2162
2163 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
2164 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2165 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2166 DWORD *pcbFormat)
2167 {
2168 CERT_ENHKEY_USAGE *usage;
2169 DWORD size;
2170 BOOL ret = FALSE;
2171
2172 if (!cbEncoded)
2173 {
2174 SetLastError(E_INVALIDARG);
2175 return FALSE;
2176 }
2177 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
2178 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
2179 {
2180 WCHAR unknown[MAX_STRING_RESOURCE_LEN];
2181 DWORD i;
2182 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
2183 LPCWSTR sep;
2184 DWORD sepLen;
2185
2186 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2187 {
2188 sep = crlf;
2189 sepLen = strlenW(crlf) * sizeof(WCHAR);
2190 }
2191 else
2192 {
2193 sep = commaSpace;
2194 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2195 }
2196
2197 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
2198 sizeof(unknown) / sizeof(unknown[0]));
2199 for (i = 0; i < usage->cUsageIdentifier; i++)
2200 {
2201 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2202 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2203
2204 if (info)
2205 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
2206 else
2207 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
2208 bytesNeeded += sizeof(WCHAR); /* space */
2209 bytesNeeded += sizeof(WCHAR); /* left paren */
2210 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
2211 sizeof(WCHAR);
2212 bytesNeeded += sizeof(WCHAR); /* right paren */
2213 if (i < usage->cUsageIdentifier - 1)
2214 bytesNeeded += sepLen;
2215 }
2216 if (!pbFormat)
2217 *pcbFormat = bytesNeeded;
2218 else if (*pcbFormat < bytesNeeded)
2219 {
2220 *pcbFormat = bytesNeeded;
2221 SetLastError(ERROR_MORE_DATA);
2222 ret = FALSE;
2223 }
2224 else
2225 {
2226 LPWSTR str = pbFormat;
2227
2228 *pcbFormat = bytesNeeded;
2229 for (i = 0; i < usage->cUsageIdentifier; i++)
2230 {
2231 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2232 usage->rgpszUsageIdentifier[i],
2233 CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
2234 LPCSTR oidPtr;
2235
2236 if (info)
2237 {
2238 strcpyW(str, info->pwszName);
2239 str += strlenW(info->pwszName);
2240 }
2241 else
2242 {
2243 strcpyW(str, unknown);
2244 str += strlenW(unknown);
2245 }
2246 *str++ = ' ';
2247 *str++ = '(';
2248 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
2249 *str++ = *oidPtr;
2250 *str++ = ')';
2251 *str = 0;
2252 if (i < usage->cUsageIdentifier - 1)
2253 {
2254 strcpyW(str, sep);
2255 str += sepLen / sizeof(WCHAR);
2256 }
2257 }
2258 }
2259 LocalFree(usage);
2260 }
2261 return ret;
2262 }
2263
2264 static struct BitToString netscapeCertTypeMap[] = {
2265 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
2266 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
2267 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
2268 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
2269 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
2270 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
2271 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
2272 };
2273
2274 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
2275 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2276 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2277 DWORD *pcbFormat)
2278 {
2279 DWORD size;
2280 CRYPT_BIT_BLOB *bits;
2281 BOOL ret;
2282
2283 if (!cbEncoded)
2284 {
2285 SetLastError(E_INVALIDARG);
2286 return FALSE;
2287 }
2288 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2289 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
2290 {
2291 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
2292 DWORD bytesNeeded = sizeof(WCHAR);
2293
2294 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
2295 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
2296 if (!bits->cbData || bits->cbData > 1)
2297 {
2298 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
2299 if (!pbFormat)
2300 *pcbFormat = bytesNeeded;
2301 else if (*pcbFormat < bytesNeeded)
2302 {
2303 *pcbFormat = bytesNeeded;
2304 SetLastError(ERROR_MORE_DATA);
2305 ret = FALSE;
2306 }
2307 else
2308 {
2309 LPWSTR str = pbFormat;
2310
2311 *pcbFormat = bytesNeeded;
2312 strcpyW(str, infoNotAvailable);
2313 }
2314 }
2315 else
2316 {
2317 static BOOL stringsLoaded = FALSE;
2318 unsigned int i;
2319 DWORD bitStringLen;
2320 BOOL first = TRUE;
2321
2322 if (!stringsLoaded)
2323 {
2324 for (i = 0; i < sizeof(netscapeCertTypeMap) /
2325 sizeof(netscapeCertTypeMap[0]); i++)
2326 LoadStringW(hInstance, netscapeCertTypeMap[i].id,
2327 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
2328 stringsLoaded = TRUE;
2329 }
2330 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2331 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2332 NULL, &bitStringLen, &first);
2333 bytesNeeded += bitStringLen;
2334 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
2335 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2336 bits->cbData, NULL, &size);
2337 bytesNeeded += size;
2338 if (!pbFormat)
2339 *pcbFormat = bytesNeeded;
2340 else if (*pcbFormat < bytesNeeded)
2341 {
2342 *pcbFormat = bytesNeeded;
2343 SetLastError(ERROR_MORE_DATA);
2344 ret = FALSE;
2345 }
2346 else
2347 {
2348 LPWSTR str = pbFormat;
2349
2350 bitStringLen = bytesNeeded;
2351 first = TRUE;
2352 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
2353 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
2354 str, &bitStringLen, &first);
2355 str += bitStringLen / sizeof(WCHAR) - 1;
2356 *str++ = ' ';
2357 *str++ = '(';
2358 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
2359 bits->cbData, str, &size);
2360 str += size / sizeof(WCHAR) - 1;
2361 *str++ = ')';
2362 *str = 0;
2363 }
2364 }
2365 LocalFree(bits);
2366 }
2367 return ret;
2368 }
2369
2370 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
2371 static WCHAR available[MAX_STRING_RESOURCE_LEN];
2372 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
2373 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
2374 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
2375 static WCHAR no[MAX_STRING_RESOURCE_LEN];
2376
2377 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
2378 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2379 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2380 DWORD *pcbFormat)
2381 {
2382 SPC_FINANCIAL_CRITERIA criteria;
2383 DWORD size = sizeof(criteria);
2384 BOOL ret = FALSE;
2385
2386 if (!cbEncoded)
2387 {
2388 SetLastError(E_INVALIDARG);
2389 return FALSE;
2390 }
2391 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
2392 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
2393 &size)))
2394 {
2395 static BOOL stringsLoaded = FALSE;
2396 DWORD bytesNeeded = sizeof(WCHAR);
2397 LPCWSTR sep;
2398 DWORD sepLen;
2399
2400 if (!stringsLoaded)
2401 {
2402 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
2403 sizeof(financialCriteria) / sizeof(financialCriteria[0]));
2404 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
2405 sizeof(available) / sizeof(available[0]));
2406 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
2407 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
2408 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
2409 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
2410 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
2411 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
2412 stringsLoaded = TRUE;
2413 }
2414 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
2415 {
2416 sep = crlf;
2417 sepLen = strlenW(crlf) * sizeof(WCHAR);
2418 }
2419 else
2420 {
2421 sep = commaSpace;
2422 sepLen = strlenW(commaSpace) * sizeof(WCHAR);
2423 }
2424 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
2425 if (criteria.fFinancialInfoAvailable)
2426 {
2427 bytesNeeded += strlenW(available) * sizeof(WCHAR);
2428 bytesNeeded += sepLen;
2429 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
2430 if (criteria.fMeetsCriteria)
2431 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
2432 else
2433 bytesNeeded += strlenW(no) * sizeof(WCHAR);
2434 }
2435 else
2436 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
2437 if (!pbFormat)
2438 *pcbFormat = bytesNeeded;
2439 else if (*pcbFormat < bytesNeeded)
2440 {
2441 *pcbFormat = bytesNeeded;
2442 SetLastError(ERROR_MORE_DATA);
2443 ret = FALSE;
2444 }
2445 else
2446 {
2447 LPWSTR str = pbFormat;
2448
2449 *pcbFormat = bytesNeeded;
2450 strcpyW(str, financialCriteria);
2451 str += strlenW(financialCriteria);
2452 if (criteria.fFinancialInfoAvailable)
2453 {
2454 strcpyW(str, available);
2455 str += strlenW(available);
2456 strcpyW(str, sep);
2457 str += sepLen / sizeof(WCHAR);
2458 strcpyW(str, meetsCriteria);
2459 str += strlenW(meetsCriteria);
2460 if (criteria.fMeetsCriteria)
2461 strcpyW(str, yes);
2462 else
2463 strcpyW(str, no);
2464 }
2465 else
2466 {
2467 strcpyW(str, notAvailable);
2468 }
2469 }
2470 }
2471 return ret;
2472 }
2473
2474 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
2475 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
2476 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
2477 DWORD *pcbFormat)
2478 {
2479 CERT_NAME_VALUE *value;
2480 DWORD size;
2481 BOOL ret;
2482
2483 if (!cbEncoded)
2484 {
2485 SetLastError(E_INVALIDARG);
2486 return FALSE;
2487 }
2488 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
2489 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
2490 {
2491 if (!pbFormat)
2492 *pcbFormat = value->Value.cbData;
2493 else if (*pcbFormat < value->Value.cbData)
2494 {
2495 *pcbFormat = value->Value.cbData;
2496 SetLastError(ERROR_MORE_DATA);
2497 ret = FALSE;
2498 }
2499 else
2500 {
2501 LPWSTR str = pbFormat;
2502
2503 *pcbFormat = value->Value.cbData;
2504 strcpyW(str, (LPWSTR)value->Value.pbData);
2505 }
2506 }
2507 return ret;
2508 }
2509
2510 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
2511 LPCSTR, const BYTE *, DWORD, void *, DWORD *);
2512
2513 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
2514 DWORD formatStrType, LPCSTR lpszStructType)
2515 {
2516 CryptFormatObjectFunc format = NULL;
2517
2518 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2519 {
2520 SetLastError(ERROR_FILE_NOT_FOUND);
2521 return NULL;
2522 }
2523 if (IS_INTOID(lpszStructType))
2524 {
2525 switch (LOWORD(lpszStructType))
2526 {
2527 case LOWORD(X509_KEY_USAGE):
2528 format = CRYPT_FormatKeyUsage;
2529 break;
2530 case LOWORD(X509_ALTERNATE_NAME):
2531 format = CRYPT_FormatAltName;
2532 break;
2533 case LOWORD(X509_BASIC_CONSTRAINTS2):
2534 format = CRYPT_FormatBasicConstraints2;
2535 break;
2536 case LOWORD(X509_AUTHORITY_KEY_ID2):
2537 format = CRYPT_FormatAuthorityKeyId2;
2538 break;
2539 case LOWORD(X509_AUTHORITY_INFO_ACCESS):
2540 format = CRYPT_FormatAuthorityInfoAccess;
2541 break;
2542 case LOWORD(X509_CRL_DIST_POINTS):
2543 format = CRYPT_FormatCRLDistPoints;
2544 break;
2545 case LOWORD(X509_ENHANCED_KEY_USAGE):
2546 format = CRYPT_FormatEnhancedKeyUsage;
2547 break;
2548 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
2549 format = CRYPT_FormatSpcFinancialCriteria;
2550 break;
2551 }
2552 }
2553 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2554 format = CRYPT_FormatAltName;
2555 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2556 format = CRYPT_FormatAltName;
2557 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2558 format = CRYPT_FormatKeyUsage;
2559 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2560 format = CRYPT_FormatAltName;
2561 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2562 format = CRYPT_FormatAltName;
2563 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2564 format = CRYPT_FormatBasicConstraints2;
2565 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
2566 format = CRYPT_FormatAuthorityInfoAccess;
2567 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
2568 format = CRYPT_FormatAuthorityKeyId2;
2569 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2570 format = CRYPT_FormatCRLDistPoints;
2571 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2572 format = CRYPT_FormatEnhancedKeyUsage;
2573 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
2574 format = CRYPT_FormatNetscapeCertType;
2575 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
2576 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
2577 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
2578 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
2579 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
2580 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
2581 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
2582 format = CRYPT_FormatUnicodeString;
2583 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
2584 format = CRYPT_FormatSpcFinancialCriteria;
2585 return format;
2586 }
2587
2588 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
2589 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
2590 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
2591 {
2592 CryptFormatObjectFunc format = NULL;
2593 HCRYPTOIDFUNCADDR hFunc = NULL;
2594 BOOL ret = FALSE;
2595
2596 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
2597 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
2598 pbEncoded, cbEncoded, pbFormat, pcbFormat);
2599
2600 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
2601 dwFormatStrType, lpszStructType)))
2602 {
2603 static HCRYPTOIDFUNCSET set = NULL;
2604
2605 if (!set)
2606 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
2607 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2608 (void **)&format, &hFunc);
2609 }
2610 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
2611 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
2612 format = CRYPT_FormatHexString;
2613 if (format)
2614 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
2615 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
2616 pcbFormat);
2617 if (hFunc)
2618 CryptFreeOIDFunctionAddress(hFunc, 0);
2619 return ret;
2620 }