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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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