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