source: trunk/src/crypt32/object.c@ 21311

Last change on this file since 21311 was 21311, checked in by vladest, 16 years ago

Added CRYPT32 and MSCMS APIs support

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