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, 933 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); 934 if (!bits->cbData || bits->cbData > 2) 935 { 936 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); 937 if (!pbFormat) 938 *pcbFormat = bytesNeeded; 939 else if (*pcbFormat < bytesNeeded) 940 { 941 *pcbFormat = bytesNeeded; 942 SetLastError(ERROR_MORE_DATA); 943 ret = FALSE; 944 } 945 else 946 { 947 LPWSTR str = pbFormat; 948 949 *pcbFormat = bytesNeeded; 950 strcpyW(str, infoNotAvailable); 951 } 952 } 953 else 954 { 955 static BOOL stringsLoaded = FALSE; 956 unsigned int i; 957 DWORD bitStringLen; 958 BOOL first = TRUE; 959 960 if (!stringsLoaded) 961 { 962 for (i = 0; 963 i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]); 964 i++) 965 LoadStringW(hInstance, keyUsageByte0Map[i].id, 966 keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN); 967 for (i = 0; 968 i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]); 969 i++) 970 LoadStringW(hInstance, keyUsageByte1Map[i].id, 971 keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN); 972 stringsLoaded = TRUE; 973 } 974 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, 975 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]), 976 NULL, &bitStringLen, &first); 977 bytesNeeded += bitStringLen; 978 if (bits->cbData == 2) 979 { 980 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, 981 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]), 982 NULL, &bitStringLen, &first); 983 bytesNeeded += bitStringLen; 984 } 985 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */ 986 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, 987 bits->cbData, NULL, &size); 988 bytesNeeded += size; 989 if (!pbFormat) 990 *pcbFormat = bytesNeeded; 991 else if (*pcbFormat < bytesNeeded) 992 { 993 *pcbFormat = bytesNeeded; 994 SetLastError(ERROR_MORE_DATA); 995 ret = FALSE; 996 } 997 else 998 { 999 LPWSTR str = pbFormat; 1000 1001 bitStringLen = bytesNeeded; 1002 first = TRUE; 1003 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map, 1004 sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]), 1005 str, &bitStringLen, &first); 1006 str += bitStringLen / sizeof(WCHAR) - 1; 1007 if (bits->cbData == 2) 1008 { 1009 bitStringLen = bytesNeeded; 1010 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map, 1011 sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]), 1012 str, &bitStringLen, &first); 1013 str += bitStringLen / sizeof(WCHAR) - 1; 1014 } 1015 *str++ = ' '; 1016 *str++ = '('; 1017 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, 1018 bits->cbData, str, &size); 1019 str += size / sizeof(WCHAR) - 1; 1020 *str++ = ')'; 1021 *str = 0; 1022 } 1023 } 1024 LocalFree(bits); 1025 } 1026 return ret; 1027 } 1028 1029 static const WCHAR crlf[] = { '\r','\n',0 }; 1030 1031 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN]; 1032 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN]; 1033 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN]; 1034 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN]; 1035 1036 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType, 1037 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 1038 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 1039 DWORD *pcbFormat) 1040 { 1041 DWORD size; 1042 CERT_BASIC_CONSTRAINTS2_INFO *info; 1043 BOOL ret; 1044 1045 if (!cbEncoded) 1046 { 1047 SetLastError(E_INVALIDARG); 1048 return FALSE; 1049 } 1050 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2, 1051 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) 1052 { 1053 static const WCHAR pathFmt[] = { '%','d',0 }; 1054 static BOOL stringsLoaded = FALSE; 1055 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */ 1056 WCHAR pathLength[MAX_STRING_RESOURCE_LEN]; 1057 LPCWSTR sep, subjectType; 1058 DWORD sepLen; 1059 1060 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1061 { 1062 sep = crlf; 1063 sepLen = strlenW(crlf) * sizeof(WCHAR); 1064 } 1065 else 1066 { 1067 sep = commaSpace; 1068 sepLen = strlenW(commaSpace) * sizeof(WCHAR); 1069 } 1070 1071 if (!stringsLoaded) 1072 { 1073 LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader, 1074 sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0])); 1075 LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA, 1076 sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0])); 1077 LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT, 1078 subjectTypeEndCert, 1079 sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0])); 1080 LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader, 1081 sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0])); 1082 stringsLoaded = TRUE; 1083 } 1084 bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR); 1085 if (info->fCA) 1086 subjectType = subjectTypeCA; 1087 else 1088 subjectType = subjectTypeEndCert; 1089 bytesNeeded += strlenW(subjectType) * sizeof(WCHAR); 1090 bytesNeeded += sepLen; 1091 bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR); 1092 if (info->fPathLenConstraint) 1093 sprintfW(pathLength, pathFmt, info->dwPathLenConstraint); 1094 else 1095 LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength, 1096 sizeof(pathLength) / sizeof(pathLength[0])); 1097 bytesNeeded += strlenW(pathLength) * sizeof(WCHAR); 1098 if (!pbFormat) 1099 *pcbFormat = bytesNeeded; 1100 else if (*pcbFormat < bytesNeeded) 1101 { 1102 *pcbFormat = bytesNeeded; 1103 SetLastError(ERROR_MORE_DATA); 1104 ret = FALSE; 1105 } 1106 else 1107 { 1108 LPWSTR str = pbFormat; 1109 1110 *pcbFormat = bytesNeeded; 1111 strcpyW(str, subjectTypeHeader); 1112 str += strlenW(subjectTypeHeader); 1113 strcpyW(str, subjectType); 1114 str += strlenW(subjectType); 1115 strcpyW(str, sep); 1116 str += sepLen / sizeof(WCHAR); 1117 strcpyW(str, pathLengthHeader); 1118 str += strlenW(pathLengthHeader); 1119 strcpyW(str, pathLength); 1120 } 1121 LocalFree(info); 1122 } 1123 return ret; 1124 } 1125 1126 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id, 1127 LPWSTR str, DWORD *pcbStr) 1128 { 1129 WCHAR buf[MAX_STRING_RESOURCE_LEN]; 1130 DWORD bytesNeeded; 1131 BOOL ret; 1132 1133 LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0])); 1134 CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL, 1135 blob->pbData, blob->cbData, NULL, &bytesNeeded); 1136 bytesNeeded += strlenW(buf) * sizeof(WCHAR); 1137 if (!str) 1138 { 1139 *pcbStr = bytesNeeded; 1140 ret = TRUE; 1141 } 1142 else if (*pcbStr < bytesNeeded) 1143 { 1144 *pcbStr = bytesNeeded; 1145 SetLastError(ERROR_MORE_DATA); 1146 ret = FALSE; 1147 } 1148 else 1149 { 1150 *pcbStr = bytesNeeded; 1151 strcpyW(str, buf); 1152 str += strlenW(str); 1153 bytesNeeded -= strlenW(str) * sizeof(WCHAR); 1154 ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL, 1155 blob->pbData, blob->cbData, str, &bytesNeeded); 1156 } 1157 return ret; 1158 } 1159 1160 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str, 1161 DWORD *pcbStr) 1162 { 1163 return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr); 1164 } 1165 1166 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str, 1167 DWORD *pcbStr) 1168 { 1169 return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER, 1170 str, pcbStr); 1171 } 1172 1173 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 }; 1174 static const WCHAR colonCrlf[] = { ':','\r','\n',0 }; 1175 1176 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel, 1177 const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr) 1178 { 1179 BOOL ret; 1180 WCHAR buf[MAX_STRING_RESOURCE_LEN]; 1181 WCHAR mask[MAX_STRING_RESOURCE_LEN]; 1182 WCHAR ipAddrBuf[32]; 1183 WCHAR maskBuf[16]; 1184 DWORD bytesNeeded = sizeof(WCHAR); 1185 DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG; 1186 1187 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1188 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR); 1189 switch (entry->dwAltNameChoice) 1190 { 1191 case CERT_ALT_NAME_RFC822_NAME: 1192 LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf, 1193 sizeof(buf) / sizeof(buf[0])); 1194 bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR); 1195 ret = TRUE; 1196 break; 1197 case CERT_ALT_NAME_DNS_NAME: 1198 LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf, 1199 sizeof(buf) / sizeof(buf[0])); 1200 bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR); 1201 ret = TRUE; 1202 break; 1203 case CERT_ALT_NAME_DIRECTORY_NAME: 1204 { 1205 DWORD directoryNameLen; 1206 1207 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1208 strType |= CERT_NAME_STR_CRLF_FLAG; 1209 directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING, 1210 indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0); 1211 LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf, 1212 sizeof(buf) / sizeof(buf[0])); 1213 bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR); 1214 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1215 bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR); 1216 else 1217 bytesNeeded += sizeof(WCHAR); /* '=' */ 1218 ret = TRUE; 1219 break; 1220 } 1221 case CERT_ALT_NAME_URL: 1222 LoadStringW(hInstance, IDS_ALT_NAME_URL, buf, 1223 sizeof(buf) / sizeof(buf[0])); 1224 bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR); 1225 ret = TRUE; 1226 break; 1227 case CERT_ALT_NAME_IP_ADDRESS: 1228 { 1229 static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.', 1230 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0 1231 }; 1232 static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d', 1233 '.','%','d',0 }; 1234 1235 LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf, 1236 sizeof(buf) / sizeof(buf[0])); 1237 if (entry->u.IPAddress.cbData == 8) 1238 { 1239 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1240 { 1241 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask, 1242 sizeof(mask) / sizeof(mask[0])); 1243 bytesNeeded += strlenW(mask) * sizeof(WCHAR); 1244 sprintfW(ipAddrBuf, ipAddrFmt, 1245 entry->u.IPAddress.pbData[0], 1246 entry->u.IPAddress.pbData[1], 1247 entry->u.IPAddress.pbData[2], 1248 entry->u.IPAddress.pbData[3]); 1249 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR); 1250 /* indent again, for the mask line */ 1251 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR); 1252 sprintfW(maskBuf, ipAddrFmt, 1253 entry->u.IPAddress.pbData[4], 1254 entry->u.IPAddress.pbData[5], 1255 entry->u.IPAddress.pbData[6], 1256 entry->u.IPAddress.pbData[7]); 1257 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR); 1258 bytesNeeded += strlenW(crlf) * sizeof(WCHAR); 1259 } 1260 else 1261 { 1262 sprintfW(ipAddrBuf, ipAddrWithMaskFmt, 1263 entry->u.IPAddress.pbData[0], 1264 entry->u.IPAddress.pbData[1], 1265 entry->u.IPAddress.pbData[2], 1266 entry->u.IPAddress.pbData[3], 1267 entry->u.IPAddress.pbData[4], 1268 entry->u.IPAddress.pbData[5], 1269 entry->u.IPAddress.pbData[6], 1270 entry->u.IPAddress.pbData[7]); 1271 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR); 1272 } 1273 ret = TRUE; 1274 } 1275 else 1276 { 1277 FIXME("unknown IP address format (%d bytes)\n", 1278 entry->u.IPAddress.cbData); 1279 ret = FALSE; 1280 } 1281 break; 1282 } 1283 default: 1284 FIXME("unimplemented for %d\n", entry->dwAltNameChoice); 1285 ret = FALSE; 1286 } 1287 if (ret) 1288 { 1289 bytesNeeded += strlenW(buf) * sizeof(WCHAR); 1290 if (!str) 1291 *pcbStr = bytesNeeded; 1292 else if (*pcbStr < bytesNeeded) 1293 { 1294 *pcbStr = bytesNeeded; 1295 SetLastError(ERROR_MORE_DATA); 1296 ret = FALSE; 1297 } 1298 else 1299 { 1300 DWORD i; 1301 1302 *pcbStr = bytesNeeded; 1303 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1304 { 1305 for (i = 0; i < indentLevel; i++) 1306 { 1307 strcpyW(str, indent); 1308 str += strlenW(indent); 1309 } 1310 } 1311 strcpyW(str, buf); 1312 str += strlenW(str); 1313 switch (entry->dwAltNameChoice) 1314 { 1315 case CERT_ALT_NAME_RFC822_NAME: 1316 case CERT_ALT_NAME_DNS_NAME: 1317 case CERT_ALT_NAME_URL: 1318 strcpyW(str, entry->u.pwszURL); 1319 break; 1320 case CERT_ALT_NAME_DIRECTORY_NAME: 1321 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1322 { 1323 strcpyW(str, colonCrlf); 1324 str += strlenW(colonCrlf); 1325 } 1326 else 1327 *str++ = '='; 1328 cert_name_to_str_with_indent(X509_ASN_ENCODING, 1329 indentLevel + 1, &entry->u.DirectoryName, strType, str, 1330 bytesNeeded / sizeof(WCHAR)); 1331 break; 1332 case CERT_ALT_NAME_IP_ADDRESS: 1333 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1334 { 1335 strcpyW(str, ipAddrBuf); 1336 str += strlenW(ipAddrBuf); 1337 strcpyW(str, crlf); 1338 str += strlenW(crlf); 1339 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1340 { 1341 for (i = 0; i < indentLevel; i++) 1342 { 1343 strcpyW(str, indent); 1344 str += strlenW(indent); 1345 } 1346 } 1347 strcpyW(str, mask); 1348 str += strlenW(mask); 1349 strcpyW(str, maskBuf); 1350 } 1351 else 1352 strcpyW(str, ipAddrBuf); 1353 break; 1354 } 1355 } 1356 } 1357 return ret; 1358 } 1359 1360 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel, 1361 const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr) 1362 { 1363 DWORD i, size, bytesNeeded = 0; 1364 BOOL ret = TRUE; 1365 LPCWSTR sep; 1366 DWORD sepLen; 1367 1368 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1369 { 1370 sep = crlf; 1371 sepLen = strlenW(crlf) * sizeof(WCHAR); 1372 } 1373 else 1374 { 1375 sep = commaSpace; 1376 sepLen = strlenW(commaSpace) * sizeof(WCHAR); 1377 } 1378 1379 for (i = 0; ret && i < name->cAltEntry; i++) 1380 { 1381 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel, 1382 &name->rgAltEntry[i], NULL, &size); 1383 if (ret) 1384 { 1385 bytesNeeded += size - sizeof(WCHAR); 1386 if (i < name->cAltEntry - 1) 1387 bytesNeeded += sepLen; 1388 } 1389 } 1390 if (ret) 1391 { 1392 bytesNeeded += sizeof(WCHAR); 1393 if (!str) 1394 *pcbStr = bytesNeeded; 1395 else if (*pcbStr < bytesNeeded) 1396 { 1397 *pcbStr = bytesNeeded; 1398 SetLastError(ERROR_MORE_DATA); 1399 ret = FALSE; 1400 } 1401 else 1402 { 1403 *pcbStr = bytesNeeded; 1404 for (i = 0; ret && i < name->cAltEntry; i++) 1405 { 1406 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel, 1407 &name->rgAltEntry[i], str, &size); 1408 if (ret) 1409 { 1410 str += size / sizeof(WCHAR) - 1; 1411 if (i < name->cAltEntry - 1) 1412 { 1413 strcpyW(str, sep); 1414 str += sepLen / sizeof(WCHAR); 1415 } 1416 } 1417 } 1418 } 1419 } 1420 return ret; 1421 } 1422 1423 static const WCHAR colonSep[] = { ':',' ',0 }; 1424 1425 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType, 1426 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 1427 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 1428 DWORD *pcbFormat) 1429 { 1430 BOOL ret; 1431 CERT_ALT_NAME_INFO *info; 1432 DWORD size; 1433 1434 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME, 1435 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) 1436 { 1437 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat); 1438 LocalFree(info); 1439 } 1440 return ret; 1441 } 1442 1443 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType, 1444 const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr) 1445 { 1446 WCHAR buf[MAX_STRING_RESOURCE_LEN]; 1447 DWORD bytesNeeded, sepLen; 1448 LPCWSTR sep; 1449 BOOL ret; 1450 1451 LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0])); 1452 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL, 1453 &bytesNeeded); 1454 bytesNeeded += strlenW(buf) * sizeof(WCHAR); 1455 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1456 { 1457 sep = colonCrlf; 1458 sepLen = strlenW(colonCrlf) * sizeof(WCHAR); 1459 } 1460 else 1461 { 1462 sep = colonSep; 1463 sepLen = strlenW(colonSep) * sizeof(WCHAR); 1464 } 1465 bytesNeeded += sepLen; 1466 if (ret) 1467 { 1468 if (!str) 1469 *pcbStr = bytesNeeded; 1470 else if (*pcbStr < bytesNeeded) 1471 { 1472 *pcbStr = bytesNeeded; 1473 SetLastError(ERROR_MORE_DATA); 1474 ret = FALSE; 1475 } 1476 else 1477 { 1478 *pcbStr = bytesNeeded; 1479 strcpyW(str, buf); 1480 bytesNeeded -= strlenW(str) * sizeof(WCHAR); 1481 str += strlenW(str); 1482 strcpyW(str, sep); 1483 str += sepLen / sizeof(WCHAR); 1484 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str, 1485 &bytesNeeded); 1486 } 1487 } 1488 return ret; 1489 } 1490 1491 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType, 1492 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 1493 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 1494 DWORD *pcbFormat) 1495 { 1496 CERT_AUTHORITY_KEY_ID2_INFO *info; 1497 DWORD size; 1498 BOOL ret = FALSE; 1499 1500 if (!cbEncoded) 1501 { 1502 SetLastError(E_INVALIDARG); 1503 return FALSE; 1504 } 1505 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2, 1506 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) 1507 { 1508 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */ 1509 LPCWSTR sep; 1510 DWORD sepLen; 1511 BOOL needSeparator = FALSE; 1512 1513 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1514 { 1515 sep = crlf; 1516 sepLen = strlenW(crlf) * sizeof(WCHAR); 1517 } 1518 else 1519 { 1520 sep = commaSpace; 1521 sepLen = strlenW(commaSpace) * sizeof(WCHAR); 1522 } 1523 1524 if (info->KeyId.cbData) 1525 { 1526 needSeparator = TRUE; 1527 ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size); 1528 if (ret) 1529 { 1530 /* don't include NULL-terminator more than once */ 1531 bytesNeeded += size - sizeof(WCHAR); 1532 } 1533 } 1534 if (info->AuthorityCertIssuer.cAltEntry) 1535 { 1536 if (needSeparator) 1537 bytesNeeded += sepLen; 1538 needSeparator = TRUE; 1539 ret = CRYPT_FormatCertIssuer(dwFormatStrType, 1540 &info->AuthorityCertIssuer, NULL, &size); 1541 if (ret) 1542 { 1543 /* don't include NULL-terminator more than once */ 1544 bytesNeeded += size - sizeof(WCHAR); 1545 } 1546 } 1547 if (info->AuthorityCertSerialNumber.cbData) 1548 { 1549 if (needSeparator) 1550 bytesNeeded += sepLen; 1551 ret = CRYPT_FormatCertSerialNumber( 1552 &info->AuthorityCertSerialNumber, NULL, &size); 1553 if (ret) 1554 { 1555 /* don't include NULL-terminator more than once */ 1556 bytesNeeded += size - sizeof(WCHAR); 1557 } 1558 } 1559 if (ret) 1560 { 1561 if (!pbFormat) 1562 *pcbFormat = bytesNeeded; 1563 else if (*pcbFormat < bytesNeeded) 1564 { 1565 *pcbFormat = bytesNeeded; 1566 SetLastError(ERROR_MORE_DATA); 1567 ret = FALSE; 1568 } 1569 else 1570 { 1571 LPWSTR str = pbFormat; 1572 1573 *pcbFormat = bytesNeeded; 1574 needSeparator = FALSE; 1575 if (info->KeyId.cbData) 1576 { 1577 needSeparator = TRUE; 1578 /* Overestimate size available, it's already been checked 1579 * above. 1580 */ 1581 size = bytesNeeded; 1582 ret = CRYPT_FormatKeyId(&info->KeyId, str, &size); 1583 if (ret) 1584 str += size / sizeof(WCHAR) - 1; 1585 } 1586 if (info->AuthorityCertIssuer.cAltEntry) 1587 { 1588 if (needSeparator) 1589 { 1590 strcpyW(str, sep); 1591 str += sepLen / sizeof(WCHAR); 1592 } 1593 needSeparator = TRUE; 1594 /* Overestimate size available, it's already been checked 1595 * above. 1596 */ 1597 size = bytesNeeded; 1598 ret = CRYPT_FormatCertIssuer(dwFormatStrType, 1599 &info->AuthorityCertIssuer, str, &size); 1600 if (ret) 1601 str += size / sizeof(WCHAR) - 1; 1602 } 1603 if (info->AuthorityCertSerialNumber.cbData) 1604 { 1605 if (needSeparator) 1606 { 1607 strcpyW(str, sep); 1608 str += sepLen / sizeof(WCHAR); 1609 } 1610 /* Overestimate size available, it's already been checked 1611 * above. 1612 */ 1613 size = bytesNeeded; 1614 ret = CRYPT_FormatCertSerialNumber( 1615 &info->AuthorityCertSerialNumber, str, &size); 1616 } 1617 } 1618 } 1619 LocalFree(info); 1620 } 1621 return ret; 1622 } 1623 1624 static WCHAR aia[MAX_STRING_RESOURCE_LEN]; 1625 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN]; 1626 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN]; 1627 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN]; 1628 static WCHAR unknown[MAX_STRING_RESOURCE_LEN]; 1629 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN]; 1630 1631 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType, 1632 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 1633 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 1634 DWORD *pcbFormat) 1635 { 1636 CERT_AUTHORITY_INFO_ACCESS *info; 1637 DWORD size; 1638 BOOL ret = FALSE; 1639 1640 if (!cbEncoded) 1641 { 1642 SetLastError(E_INVALIDARG); 1643 return FALSE; 1644 } 1645 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, 1646 X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, 1647 NULL, &info, &size))) 1648 { 1649 DWORD bytesNeeded = sizeof(WCHAR); 1650 1651 if (!info->cAccDescr) 1652 { 1653 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; 1654 1655 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, 1656 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); 1657 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); 1658 if (!pbFormat) 1659 *pcbFormat = bytesNeeded; 1660 else if (*pcbFormat < bytesNeeded) 1661 { 1662 *pcbFormat = bytesNeeded; 1663 SetLastError(ERROR_MORE_DATA); 1664 ret = FALSE; 1665 } 1666 else 1667 { 1668 *pcbFormat = bytesNeeded; 1669 strcpyW(pbFormat, infoNotAvailable); 1670 } 1671 } 1672 else 1673 { 1674 static const WCHAR numFmt[] = { '%','d',0 }; 1675 static const WCHAR equal[] = { '=',0 }; 1676 static BOOL stringsLoaded = FALSE; 1677 DWORD i; 1678 LPCWSTR headingSep, accessMethodSep, locationSep; 1679 WCHAR accessDescrNum[11]; 1680 1681 if (!stringsLoaded) 1682 { 1683 LoadStringW(hInstance, IDS_AIA, aia, 1684 sizeof(aia) / sizeof(aia[0])); 1685 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod, 1686 sizeof(accessMethod) / sizeof(accessMethod[0])); 1687 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp, 1688 sizeof(ocsp) / sizeof(ocsp[0])); 1689 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers, 1690 sizeof(caIssuers) / sizeof(caIssuers[0])); 1691 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown, 1692 sizeof(unknown) / sizeof(unknown[0])); 1693 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation, 1694 sizeof(accessLocation) / sizeof(accessLocation[0])); 1695 stringsLoaded = TRUE; 1696 } 1697 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1698 { 1699 headingSep = crlf; 1700 accessMethodSep = crlf; 1701 locationSep = colonCrlf; 1702 } 1703 else 1704 { 1705 headingSep = colonSep; 1706 accessMethodSep = commaSpace; 1707 locationSep = equal; 1708 } 1709 1710 for (i = 0; ret && i < info->cAccDescr; i++) 1711 { 1712 /* Heading */ 1713 bytesNeeded += sizeof(WCHAR); /* left bracket */ 1714 sprintfW(accessDescrNum, numFmt, i + 1); 1715 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR); 1716 bytesNeeded += sizeof(WCHAR); /* right bracket */ 1717 bytesNeeded += strlenW(aia) * sizeof(WCHAR); 1718 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR); 1719 /* Access method */ 1720 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR); 1721 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1722 bytesNeeded += strlenW(indent) * sizeof(WCHAR); 1723 if (!strcmp(info->rgAccDescr[i].pszAccessMethod, 1724 szOID_PKIX_OCSP)) 1725 bytesNeeded += strlenW(ocsp) * sizeof(WCHAR); 1726 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod, 1727 szOID_PKIX_CA_ISSUERS)) 1728 bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers); 1729 else 1730 bytesNeeded += strlenW(unknown) * sizeof(WCHAR); 1731 bytesNeeded += sizeof(WCHAR); /* space */ 1732 bytesNeeded += sizeof(WCHAR); /* left paren */ 1733 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod) 1734 * sizeof(WCHAR); 1735 bytesNeeded += sizeof(WCHAR); /* right paren */ 1736 /* Delimiter between access method and location */ 1737 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR); 1738 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1739 bytesNeeded += strlenW(indent) * sizeof(WCHAR); 1740 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR); 1741 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR); 1742 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2, 1743 &info->rgAccDescr[i].AccessLocation, NULL, &size); 1744 if (ret) 1745 bytesNeeded += size - sizeof(WCHAR); 1746 /* Need extra delimiter between access method entries */ 1747 if (i < info->cAccDescr - 1) 1748 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR); 1749 } 1750 if (ret) 1751 { 1752 if (!pbFormat) 1753 *pcbFormat = bytesNeeded; 1754 else if (*pcbFormat < bytesNeeded) 1755 { 1756 *pcbFormat = bytesNeeded; 1757 SetLastError(ERROR_MORE_DATA); 1758 ret = FALSE; 1759 } 1760 else 1761 { 1762 LPWSTR str = pbFormat; 1763 DWORD altNameEntrySize; 1764 1765 *pcbFormat = bytesNeeded; 1766 for (i = 0; ret && i < info->cAccDescr; i++) 1767 { 1768 LPCSTR oidPtr; 1769 1770 *str++ = '['; 1771 sprintfW(accessDescrNum, numFmt, i + 1); 1772 strcpyW(str, accessDescrNum); 1773 str += strlenW(accessDescrNum); 1774 *str++ = ']'; 1775 strcpyW(str, aia); 1776 str += strlenW(aia); 1777 strcpyW(str, headingSep); 1778 str += strlenW(headingSep); 1779 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1780 { 1781 strcpyW(str, indent); 1782 str += strlenW(indent); 1783 } 1784 strcpyW(str, accessMethod); 1785 str += strlenW(accessMethod); 1786 if (!strcmp(info->rgAccDescr[i].pszAccessMethod, 1787 szOID_PKIX_OCSP)) 1788 { 1789 strcpyW(str, ocsp); 1790 str += strlenW(ocsp); 1791 } 1792 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod, 1793 szOID_PKIX_CA_ISSUERS)) 1794 { 1795 strcpyW(str, caIssuers); 1796 str += strlenW(caIssuers); 1797 } 1798 else 1799 { 1800 strcpyW(str, unknown); 1801 str += strlenW(unknown); 1802 } 1803 *str++ = ' '; 1804 *str++ = '('; 1805 for (oidPtr = info->rgAccDescr[i].pszAccessMethod; 1806 *oidPtr; oidPtr++, str++) 1807 *str = *oidPtr; 1808 *str++ = ')'; 1809 strcpyW(str, accessMethodSep); 1810 str += strlenW(accessMethodSep); 1811 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1812 { 1813 strcpyW(str, indent); 1814 str += strlenW(indent); 1815 } 1816 strcpyW(str, accessLocation); 1817 str += strlenW(accessLocation); 1818 strcpyW(str, locationSep); 1819 str += strlenW(locationSep); 1820 /* This overestimates the size available, but that 1821 * won't matter since we checked earlier whether enough 1822 * space for the entire string was available. 1823 */ 1824 altNameEntrySize = bytesNeeded; 1825 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2, 1826 &info->rgAccDescr[i].AccessLocation, str, 1827 &altNameEntrySize); 1828 if (ret) 1829 str += altNameEntrySize / sizeof(WCHAR) - 1; 1830 if (i < info->cAccDescr - 1) 1831 { 1832 strcpyW(str, accessMethodSep); 1833 str += strlenW(accessMethodSep); 1834 } 1835 } 1836 } 1837 } 1838 } 1839 LocalFree(info); 1840 } 1841 return ret; 1842 } 1843 1844 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN]; 1845 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN]; 1846 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN]; 1847 static WCHAR superseded[MAX_STRING_RESOURCE_LEN]; 1848 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN]; 1849 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN]; 1850 1851 struct reason_map_entry 1852 { 1853 BYTE reasonBit; 1854 LPWSTR reason; 1855 int id; 1856 }; 1857 static struct reason_map_entry reason_map[] = { 1858 { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE }, 1859 { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE }, 1860 { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged, 1861 IDS_REASON_AFFILIATION_CHANGED }, 1862 { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED }, 1863 { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased, 1864 IDS_REASON_CESSATION_OF_OPERATION }, 1865 { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold, 1866 IDS_REASON_CERTIFICATE_HOLD }, 1867 }; 1868 1869 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType, 1870 const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr) 1871 { 1872 static const WCHAR sep[] = { ',',' ',0 }; 1873 static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 }; 1874 static BOOL stringsLoaded = FALSE; 1875 unsigned int i, numReasons = 0; 1876 BOOL ret = TRUE; 1877 DWORD bytesNeeded = sizeof(WCHAR); 1878 WCHAR bits[6]; 1879 1880 if (!stringsLoaded) 1881 { 1882 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) 1883 LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason, 1884 MAX_STRING_RESOURCE_LEN); 1885 stringsLoaded = TRUE; 1886 } 1887 /* No need to check reasonFlags->cbData, we already know it's positive. 1888 * Ignore any other bytes, as they're for undefined bits. 1889 */ 1890 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) 1891 { 1892 if (reasonFlags->pbData[0] & reason_map[i].reasonBit) 1893 { 1894 bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR); 1895 if (numReasons++) 1896 bytesNeeded += strlenW(sep) * sizeof(WCHAR); 1897 } 1898 } 1899 sprintfW(bits, bitsFmt, reasonFlags->pbData[0]); 1900 bytesNeeded += strlenW(bits); 1901 if (!str) 1902 *pcbStr = bytesNeeded; 1903 else if (*pcbStr < bytesNeeded) 1904 { 1905 *pcbStr = bytesNeeded; 1906 SetLastError(ERROR_MORE_DATA); 1907 ret = FALSE; 1908 } 1909 else 1910 { 1911 *pcbStr = bytesNeeded; 1912 for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++) 1913 { 1914 if (reasonFlags->pbData[0] & reason_map[i].reasonBit) 1915 { 1916 strcpyW(str, reason_map[i].reason); 1917 str += strlenW(reason_map[i].reason); 1918 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 && 1919 numReasons) 1920 { 1921 strcpyW(str, sep); 1922 str += strlenW(sep); 1923 } 1924 } 1925 } 1926 strcpyW(str, bits); 1927 } 1928 return ret; 1929 } 1930 1931 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN]; 1932 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN]; 1933 static WCHAR fullName[MAX_STRING_RESOURCE_LEN]; 1934 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN]; 1935 static WCHAR reason[MAX_STRING_RESOURCE_LEN]; 1936 static WCHAR issuer[MAX_STRING_RESOURCE_LEN]; 1937 1938 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType, 1939 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 1940 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 1941 DWORD *pcbFormat) 1942 { 1943 CRL_DIST_POINTS_INFO *info; 1944 DWORD size; 1945 BOOL ret = FALSE; 1946 1947 if (!cbEncoded) 1948 { 1949 SetLastError(E_INVALIDARG); 1950 return FALSE; 1951 } 1952 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS, 1953 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size))) 1954 { 1955 static const WCHAR numFmt[] = { '%','d',0 }; 1956 static const WCHAR colon[] = { ':',0 }; 1957 static BOOL stringsLoaded = FALSE; 1958 DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */ 1959 BOOL haveAnEntry = FALSE; 1960 LPCWSTR headingSep, nameSep; 1961 WCHAR distPointNum[11]; 1962 DWORD i; 1963 1964 if (!stringsLoaded) 1965 { 1966 LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint, 1967 sizeof(crlDistPoint) / sizeof(crlDistPoint[0])); 1968 LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName, 1969 sizeof(distPointName) / sizeof(distPointName[0])); 1970 LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName, 1971 sizeof(fullName) / sizeof(fullName[0])); 1972 LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName, 1973 sizeof(rdnName) / sizeof(rdnName[0])); 1974 LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason, 1975 sizeof(reason) / sizeof(reason[0])); 1976 LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer, 1977 sizeof(issuer) / sizeof(issuer[0])); 1978 stringsLoaded = TRUE; 1979 } 1980 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 1981 { 1982 headingSep = crlf; 1983 nameSep = colonCrlf; 1984 } 1985 else 1986 { 1987 headingSep = colonSep; 1988 nameSep = colon; 1989 } 1990 1991 for (i = 0; ret && i < info->cDistPoint; i++) 1992 { 1993 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i]; 1994 1995 if (distPoint->DistPointName.dwDistPointNameChoice != 1996 CRL_DIST_POINT_NO_NAME) 1997 { 1998 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR); 1999 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); 2000 if (distPoint->DistPointName.dwDistPointNameChoice == 2001 CRL_DIST_POINT_FULL_NAME) 2002 bytesNeeded += strlenW(fullName) * sizeof(WCHAR); 2003 else 2004 bytesNeeded += strlenW(rdnName) * sizeof(WCHAR); 2005 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); 2006 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 2007 bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR); 2008 /* The indent level (3) is higher than when used as the issuer, 2009 * because the name is subordinate to the name type (full vs. 2010 * RDN.) 2011 */ 2012 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3, 2013 &distPoint->DistPointName.u.FullName, NULL, &size); 2014 if (ret) 2015 bytesNeeded += size - sizeof(WCHAR); 2016 haveAnEntry = TRUE; 2017 } 2018 else if (distPoint->ReasonFlags.cbData) 2019 { 2020 bytesNeeded += strlenW(reason) * sizeof(WCHAR); 2021 ret = CRYPT_FormatReason(dwFormatStrType, 2022 &distPoint->ReasonFlags, NULL, &size); 2023 if (ret) 2024 bytesNeeded += size - sizeof(WCHAR); 2025 haveAnEntry = TRUE; 2026 } 2027 else if (distPoint->CRLIssuer.cAltEntry) 2028 { 2029 bytesNeeded += strlenW(issuer) * sizeof(WCHAR); 2030 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR); 2031 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2, 2032 &distPoint->CRLIssuer, NULL, &size); 2033 if (ret) 2034 bytesNeeded += size - sizeof(WCHAR); 2035 haveAnEntry = TRUE; 2036 } 2037 if (haveAnEntry) 2038 { 2039 bytesNeeded += sizeof(WCHAR); /* left bracket */ 2040 sprintfW(distPointNum, numFmt, i + 1); 2041 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR); 2042 bytesNeeded += sizeof(WCHAR); /* right bracket */ 2043 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR); 2044 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR); 2045 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 2046 bytesNeeded += strlenW(indent) * sizeof(WCHAR); 2047 } 2048 } 2049 if (!haveAnEntry) 2050 { 2051 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; 2052 2053 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, 2054 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); 2055 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); 2056 if (!pbFormat) 2057 *pcbFormat = bytesNeeded; 2058 else if (*pcbFormat < bytesNeeded) 2059 { 2060 *pcbFormat = bytesNeeded; 2061 SetLastError(ERROR_MORE_DATA); 2062 ret = FALSE; 2063 } 2064 else 2065 { 2066 *pcbFormat = bytesNeeded; 2067 strcpyW(pbFormat, infoNotAvailable); 2068 } 2069 } 2070 else 2071 { 2072 if (!pbFormat) 2073 *pcbFormat = bytesNeeded; 2074 else if (*pcbFormat < bytesNeeded) 2075 { 2076 *pcbFormat = bytesNeeded; 2077 SetLastError(ERROR_MORE_DATA); 2078 ret = FALSE; 2079 } 2080 else 2081 { 2082 LPWSTR str = pbFormat; 2083 2084 *pcbFormat = bytesNeeded; 2085 for (i = 0; ret && i < info->cDistPoint; i++) 2086 { 2087 CRL_DIST_POINT *distPoint = &info->rgDistPoint[i]; 2088 2089 *str++ = '['; 2090 sprintfW(distPointNum, numFmt, i + 1); 2091 strcpyW(str, distPointNum); 2092 str += strlenW(distPointNum); 2093 *str++ = ']'; 2094 strcpyW(str, crlDistPoint); 2095 str += strlenW(crlDistPoint); 2096 strcpyW(str, headingSep); 2097 str += strlenW(headingSep); 2098 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 2099 { 2100 strcpyW(str, indent); 2101 str += strlenW(indent); 2102 } 2103 if (distPoint->DistPointName.dwDistPointNameChoice != 2104 CRL_DIST_POINT_NO_NAME) 2105 { 2106 DWORD altNameSize = bytesNeeded; 2107 2108 strcpyW(str, distPointName); 2109 str += strlenW(distPointName); 2110 strcpyW(str, nameSep); 2111 str += strlenW(nameSep); 2112 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 2113 { 2114 strcpyW(str, indent); 2115 str += strlenW(indent); 2116 strcpyW(str, indent); 2117 str += strlenW(indent); 2118 } 2119 if (distPoint->DistPointName.dwDistPointNameChoice == 2120 CRL_DIST_POINT_FULL_NAME) 2121 { 2122 strcpyW(str, fullName); 2123 str += strlenW(fullName); 2124 } 2125 else 2126 { 2127 strcpyW(str, rdnName); 2128 str += strlenW(rdnName); 2129 } 2130 strcpyW(str, nameSep); 2131 str += strlenW(nameSep); 2132 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3, 2133 &distPoint->DistPointName.u.FullName, str, 2134 &altNameSize); 2135 if (ret) 2136 str += altNameSize / sizeof(WCHAR) - 1; 2137 } 2138 else if (distPoint->ReasonFlags.cbData) 2139 { 2140 DWORD reasonSize = bytesNeeded; 2141 2142 strcpyW(str, reason); 2143 str += strlenW(reason); 2144 ret = CRYPT_FormatReason(dwFormatStrType, 2145 &distPoint->ReasonFlags, str, &reasonSize); 2146 if (ret) 2147 str += reasonSize / sizeof(WCHAR) - 1; 2148 } 2149 else if (distPoint->CRLIssuer.cAltEntry) 2150 { 2151 DWORD crlIssuerSize = bytesNeeded; 2152 2153 strcpyW(str, issuer); 2154 str += strlenW(issuer); 2155 strcpyW(str, nameSep); 2156 str += strlenW(nameSep); 2157 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2, 2158 &distPoint->CRLIssuer, str, 2159 &crlIssuerSize); 2160 if (ret) 2161 str += crlIssuerSize / sizeof(WCHAR) - 1; 2162 } 2163 } 2164 } 2165 } 2166 LocalFree(info); 2167 } 2168 return ret; 2169 } 2170 2171 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType, 2172 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 2173 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 2174 DWORD *pcbFormat) 2175 { 2176 CERT_ENHKEY_USAGE *usage; 2177 DWORD size; 2178 BOOL ret = FALSE; 2179 2180 if (!cbEncoded) 2181 { 2182 SetLastError(E_INVALIDARG); 2183 return FALSE; 2184 } 2185 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE, 2186 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size))) 2187 { 2188 WCHAR unknown[MAX_STRING_RESOURCE_LEN]; 2189 DWORD i; 2190 DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */ 2191 LPCWSTR sep; 2192 DWORD sepLen; 2193 2194 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 2195 { 2196 sep = crlf; 2197 sepLen = strlenW(crlf) * sizeof(WCHAR); 2198 } 2199 else 2200 { 2201 sep = commaSpace; 2202 sepLen = strlenW(commaSpace) * sizeof(WCHAR); 2203 } 2204 2205 LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown, 2206 sizeof(unknown) / sizeof(unknown[0])); 2207 for (i = 0; i < usage->cUsageIdentifier; i++) 2208 { 2209 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 2210 usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID); 2211 2212 if (info) 2213 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR); 2214 else 2215 bytesNeeded += strlenW(unknown) * sizeof(WCHAR); 2216 bytesNeeded += sizeof(WCHAR); /* space */ 2217 bytesNeeded += sizeof(WCHAR); /* left paren */ 2218 bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) * 2219 sizeof(WCHAR); 2220 bytesNeeded += sizeof(WCHAR); /* right paren */ 2221 if (i < usage->cUsageIdentifier - 1) 2222 bytesNeeded += sepLen; 2223 } 2224 if (!pbFormat) 2225 *pcbFormat = bytesNeeded; 2226 else if (*pcbFormat < bytesNeeded) 2227 { 2228 *pcbFormat = bytesNeeded; 2229 SetLastError(ERROR_MORE_DATA); 2230 ret = FALSE; 2231 } 2232 else 2233 { 2234 LPWSTR str = pbFormat; 2235 2236 *pcbFormat = bytesNeeded; 2237 for (i = 0; i < usage->cUsageIdentifier; i++) 2238 { 2239 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, 2240 usage->rgpszUsageIdentifier[i], 2241 CRYPT_ENHKEY_USAGE_OID_GROUP_ID); 2242 LPCSTR oidPtr; 2243 2244 if (info) 2245 { 2246 strcpyW(str, info->pwszName); 2247 str += strlenW(info->pwszName); 2248 } 2249 else 2250 { 2251 strcpyW(str, unknown); 2252 str += strlenW(unknown); 2253 } 2254 *str++ = ' '; 2255 *str++ = '('; 2256 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++) 2257 *str++ = *oidPtr; 2258 *str++ = ')'; 2259 *str = 0; 2260 if (i < usage->cUsageIdentifier - 1) 2261 { 2262 strcpyW(str, sep); 2263 str += sepLen / sizeof(WCHAR); 2264 } 2265 } 2266 } 2267 LocalFree(usage); 2268 } 2269 return ret; 2270 } 2271 2272 static struct BitToString netscapeCertTypeMap[] = { 2273 { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } }, 2274 { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } }, 2275 { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } }, 2276 { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } }, 2277 { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } }, 2278 { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } }, 2279 { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } }, 2280 }; 2281 2282 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType, 2283 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 2284 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 2285 DWORD *pcbFormat) 2286 { 2287 DWORD size; 2288 CRYPT_BIT_BLOB *bits; 2289 BOOL ret; 2290 2291 if (!cbEncoded) 2292 { 2293 SetLastError(E_INVALIDARG); 2294 return FALSE; 2295 } 2296 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS, 2297 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size))) 2298 { 2299 WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN]; 2300 DWORD bytesNeeded = sizeof(WCHAR); 2301 2302 LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable, 2303 sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0])); 2304 if (!bits->cbData || bits->cbData > 1) 2305 { 2306 bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR); 2307 if (!pbFormat) 2308 *pcbFormat = bytesNeeded; 2309 else if (*pcbFormat < bytesNeeded) 2310 { 2311 *pcbFormat = bytesNeeded; 2312 SetLastError(ERROR_MORE_DATA); 2313 ret = FALSE; 2314 } 2315 else 2316 { 2317 LPWSTR str = pbFormat; 2318 2319 *pcbFormat = bytesNeeded; 2320 strcpyW(str, infoNotAvailable); 2321 } 2322 } 2323 else 2324 { 2325 static BOOL stringsLoaded = FALSE; 2326 unsigned int i; 2327 DWORD bitStringLen; 2328 BOOL first = TRUE; 2329 2330 if (!stringsLoaded) 2331 { 2332 for (i = 0; i < sizeof(netscapeCertTypeMap) / 2333 sizeof(netscapeCertTypeMap[0]); i++) 2334 LoadStringW(hInstance, netscapeCertTypeMap[i].id, 2335 netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN); 2336 stringsLoaded = TRUE; 2337 } 2338 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, 2339 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]), 2340 NULL, &bitStringLen, &first); 2341 bytesNeeded += bitStringLen; 2342 bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */ 2343 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, 2344 bits->cbData, NULL, &size); 2345 bytesNeeded += size; 2346 if (!pbFormat) 2347 *pcbFormat = bytesNeeded; 2348 else if (*pcbFormat < bytesNeeded) 2349 { 2350 *pcbFormat = bytesNeeded; 2351 SetLastError(ERROR_MORE_DATA); 2352 ret = FALSE; 2353 } 2354 else 2355 { 2356 LPWSTR str = pbFormat; 2357 2358 bitStringLen = bytesNeeded; 2359 first = TRUE; 2360 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap, 2361 sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]), 2362 str, &bitStringLen, &first); 2363 str += bitStringLen / sizeof(WCHAR) - 1; 2364 *str++ = ' '; 2365 *str++ = '('; 2366 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData, 2367 bits->cbData, str, &size); 2368 str += size / sizeof(WCHAR) - 1; 2369 *str++ = ')'; 2370 *str = 0; 2371 } 2372 } 2373 LocalFree(bits); 2374 } 2375 return ret; 2376 } 2377 2378 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN]; 2379 static WCHAR available[MAX_STRING_RESOURCE_LEN]; 2380 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN]; 2381 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN]; 2382 static WCHAR yes[MAX_STRING_RESOURCE_LEN]; 2383 static WCHAR no[MAX_STRING_RESOURCE_LEN]; 2384 2385 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType, 2386 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 2387 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 2388 DWORD *pcbFormat) 2389 { 2390 SPC_FINANCIAL_CRITERIA criteria; 2391 DWORD size = sizeof(criteria); 2392 BOOL ret = FALSE; 2393 2394 if (!cbEncoded) 2395 { 2396 SetLastError(E_INVALIDARG); 2397 return FALSE; 2398 } 2399 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, 2400 SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria, 2401 &size))) 2402 { 2403 static BOOL stringsLoaded = FALSE; 2404 DWORD bytesNeeded = sizeof(WCHAR); 2405 LPCWSTR sep; 2406 DWORD sepLen; 2407 2408 if (!stringsLoaded) 2409 { 2410 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria, 2411 sizeof(financialCriteria) / sizeof(financialCriteria[0])); 2412 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available, 2413 sizeof(available) / sizeof(available[0])); 2414 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE, 2415 notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0])); 2416 LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA, 2417 meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0])); 2418 LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0])); 2419 LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0])); 2420 stringsLoaded = TRUE; 2421 } 2422 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) 2423 { 2424 sep = crlf; 2425 sepLen = strlenW(crlf) * sizeof(WCHAR); 2426 } 2427 else 2428 { 2429 sep = commaSpace; 2430 sepLen = strlenW(commaSpace) * sizeof(WCHAR); 2431 } 2432 bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR); 2433 if (criteria.fFinancialInfoAvailable) 2434 { 2435 bytesNeeded += strlenW(available) * sizeof(WCHAR); 2436 bytesNeeded += sepLen; 2437 bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR); 2438 if (criteria.fMeetsCriteria) 2439 bytesNeeded += strlenW(yes) * sizeof(WCHAR); 2440 else 2441 bytesNeeded += strlenW(no) * sizeof(WCHAR); 2442 } 2443 else 2444 bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR); 2445 if (!pbFormat) 2446 *pcbFormat = bytesNeeded; 2447 else if (*pcbFormat < bytesNeeded) 2448 { 2449 *pcbFormat = bytesNeeded; 2450 SetLastError(ERROR_MORE_DATA); 2451 ret = FALSE; 2452 } 2453 else 2454 { 2455 LPWSTR str = pbFormat; 2456 2457 *pcbFormat = bytesNeeded; 2458 strcpyW(str, financialCriteria); 2459 str += strlenW(financialCriteria); 2460 if (criteria.fFinancialInfoAvailable) 2461 { 2462 strcpyW(str, available); 2463 str += strlenW(available); 2464 strcpyW(str, sep); 2465 str += sepLen / sizeof(WCHAR); 2466 strcpyW(str, meetsCriteria); 2467 str += strlenW(meetsCriteria); 2468 if (criteria.fMeetsCriteria) 2469 strcpyW(str, yes); 2470 else 2471 strcpyW(str, no); 2472 } 2473 else 2474 { 2475 strcpyW(str, notAvailable); 2476 } 2477 } 2478 } 2479 return ret; 2480 } 2481 2482 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType, 2483 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, 2484 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, 2485 DWORD *pcbFormat) 2486 { 2487 CERT_NAME_VALUE *value; 2488 DWORD size; 2489 BOOL ret; 2490 2491 if (!cbEncoded) 2492 { 2493 SetLastError(E_INVALIDARG); 2494 return FALSE; 2495 } 2496 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING, 2497 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size))) 2498 { 2499 if (!pbFormat) 2500 *pcbFormat = value->Value.cbData; 2501 else if (*pcbFormat < value->Value.cbData) 2502 { 2503 *pcbFormat = value->Value.cbData; 2504 SetLastError(ERROR_MORE_DATA); 2505 ret = FALSE; 2506 } 2507 else 2508 { 2509 LPWSTR str = pbFormat; 2510 2511 *pcbFormat = value->Value.cbData; 2512 strcpyW(str, (LPWSTR)value->Value.pbData); 2513 } 2514 } 2515 return ret; 2516 } 2517 2518 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *, 2519 LPCSTR, const BYTE *, DWORD, void *, DWORD *); 2520 2521 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType, 2522 DWORD formatStrType, LPCSTR lpszStructType) 2523 { 2524 CryptFormatObjectFunc format = NULL; 2525 2526 if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING) 2527 { 2528 SetLastError(ERROR_FILE_NOT_FOUND); 2529 return NULL; 2530 } 2531 if (IS_INTOID(lpszStructType)) 2532 { 2533 switch (LOWORD(lpszStructType)) 2534 { 2535 case LOWORD(X509_KEY_USAGE): 2536 format = CRYPT_FormatKeyUsage; 2537 break; 2538 case LOWORD(X509_ALTERNATE_NAME): 2539 format = CRYPT_FormatAltName; 2540 break; 2541 case LOWORD(X509_BASIC_CONSTRAINTS2): 2542 format = CRYPT_FormatBasicConstraints2; 2543 break; 2544 case LOWORD(X509_AUTHORITY_KEY_ID2): 2545 format = CRYPT_FormatAuthorityKeyId2; 2546 break; 2547 case LOWORD(X509_AUTHORITY_INFO_ACCESS): 2548 format = CRYPT_FormatAuthorityInfoAccess; 2549 break; 2550 case LOWORD(X509_CRL_DIST_POINTS): 2551 format = CRYPT_FormatCRLDistPoints; 2552 break; 2553 case LOWORD(X509_ENHANCED_KEY_USAGE): 2554 format = CRYPT_FormatEnhancedKeyUsage; 2555 break; 2556 case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT): 2557 format = CRYPT_FormatSpcFinancialCriteria; 2558 break; 2559 } 2560 } 2561 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME)) 2562 format = CRYPT_FormatAltName; 2563 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME)) 2564 format = CRYPT_FormatAltName; 2565 else if (!strcmp(lpszStructType, szOID_KEY_USAGE)) 2566 format = CRYPT_FormatKeyUsage; 2567 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2)) 2568 format = CRYPT_FormatAltName; 2569 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2)) 2570 format = CRYPT_FormatAltName; 2571 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2)) 2572 format = CRYPT_FormatBasicConstraints2; 2573 else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS)) 2574 format = CRYPT_FormatAuthorityInfoAccess; 2575 else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2)) 2576 format = CRYPT_FormatAuthorityKeyId2; 2577 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS)) 2578 format = CRYPT_FormatCRLDistPoints; 2579 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE)) 2580 format = CRYPT_FormatEnhancedKeyUsage; 2581 else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE)) 2582 format = CRYPT_FormatNetscapeCertType; 2583 else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) || 2584 !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) || 2585 !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) || 2586 !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) || 2587 !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) || 2588 !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) || 2589 !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT)) 2590 format = CRYPT_FormatUnicodeString; 2591 else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID)) 2592 format = CRYPT_FormatSpcFinancialCriteria; 2593 return format; 2594 } 2595 2596 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType, 2597 DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType, 2598 const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat) 2599 { 2600 CryptFormatObjectFunc format = NULL; 2601 HCRYPTOIDFUNCADDR hFunc = NULL; 2602 BOOL ret = FALSE; 2603 2604 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType, 2605 dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType), 2606 pbEncoded, cbEncoded, pbFormat, pcbFormat); 2607 2608 if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType, 2609 dwFormatStrType, lpszStructType))) 2610 { 2611 static HCRYPTOIDFUNCSET set = NULL; 2612 2613 if (!set) 2614 set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0); 2615 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0, 2616 (void **)&format, &hFunc); 2617 } 2618 if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == 2619 X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX)) 2620 format = CRYPT_FormatHexString; 2621 if (format) 2622 ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType, 2623 pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat, 2624 pcbFormat); 2625 if (hFunc) 2626 CryptFreeOIDFunctionAddress(hFunc, 0); 2627 return ret; 2628 } 2629