1 /* 2 * Copyright 2004-2007 Juan Lang 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "config.h" 20 #include "wine/port.h" 21 22 #include <stdarg.h> 23 #include "windef.h" 24 #include "winbase.h" 25 #include "wincrypt.h" 26 #include "wine/debug.h" 27 #include "wine/exception.h" 28 #include "crypt32_private.h" 29 30 WINE_DEFAULT_DEBUG_CHANNEL(crypt); 31 32 /* An extended certificate property in serialized form is prefixed by this 33 * header. 34 */ 35 typedef struct _WINE_CERT_PROP_HEADER 36 { 37 DWORD propID; 38 DWORD unknown; /* always 1 */ 39 DWORD cb; 40 } WINE_CERT_PROP_HEADER; 41 42 static BOOL CRYPT_SerializeStoreElement(const void *context, 43 const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID, 44 const WINE_CONTEXT_INTERFACE *contextInterface, DWORD dwFlags, BOOL omitHashes, 45 BYTE *pbElement, DWORD *pcbElement) 46 { 47 BOOL ret; 48 49 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags, 50 omitHashes, pbElement, pcbElement); 51 52 if (context) 53 { 54 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext; 55 DWORD prop = 0; 56 57 ret = TRUE; 58 do { 59 prop = contextInterface->enumProps(context, prop); 60 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop))) 61 { 62 DWORD propSize = 0; 63 64 ret = contextInterface->getProp(context, prop, NULL, &propSize); 65 if (ret) 66 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize; 67 } 68 } while (ret && prop != 0); 69 70 if (!pbElement) 71 { 72 *pcbElement = bytesNeeded; 73 ret = TRUE; 74 } 75 else if (*pcbElement < bytesNeeded) 76 { 77 *pcbElement = bytesNeeded; 78 SetLastError(ERROR_MORE_DATA); 79 ret = FALSE; 80 } 81 else 82 { 83 WINE_CERT_PROP_HEADER *hdr; 84 DWORD bufSize = 0; 85 LPBYTE buf = NULL; 86 87 prop = 0; 88 do { 89 prop = contextInterface->enumProps(context, prop); 90 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop))) 91 { 92 DWORD propSize = 0; 93 94 ret = contextInterface->getProp(context, prop, NULL, 95 &propSize); 96 if (ret) 97 { 98 if (bufSize < propSize) 99 { 100 if (buf) 101 buf = CryptMemRealloc(buf, propSize); 102 else 103 buf = CryptMemAlloc(propSize); 104 bufSize = propSize; 105 } 106 if (buf) 107 { 108 ret = contextInterface->getProp(context, prop, buf, 109 &propSize); 110 if (ret) 111 { 112 hdr = (WINE_CERT_PROP_HEADER*)pbElement; 113 hdr->propID = prop; 114 hdr->unknown = 1; 115 hdr->cb = propSize; 116 pbElement += sizeof(WINE_CERT_PROP_HEADER); 117 if (propSize) 118 { 119 memcpy(pbElement, buf, propSize); 120 pbElement += propSize; 121 } 122 } 123 } 124 else 125 ret = FALSE; 126 } 127 } 128 } while (ret && prop != 0); 129 CryptMemFree(buf); 130 131 hdr = (WINE_CERT_PROP_HEADER*)pbElement; 132 hdr->propID = contextPropID; 133 hdr->unknown = 1; 134 hdr->cb = cbEncodedContext; 135 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER), 136 encodedContext, cbEncodedContext); 137 } 138 } 139 else 140 ret = FALSE; 141 return ret; 142 } 143 144 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext, 145 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) 146 { 147 return CRYPT_SerializeStoreElement(pCertContext, 148 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, 149 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement); 150 } 151 152 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext, 153 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) 154 { 155 return CRYPT_SerializeStoreElement(pCrlContext, 156 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded, 157 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement); 158 } 159 160 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext, 161 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) 162 { 163 return CRYPT_SerializeStoreElement(pCtlContext, 164 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded, 165 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement); 166 } 167 168 /* Looks for the property with ID propID in the buffer buf. Returns a pointer 169 * to its header if a valid header is found, NULL if not. Valid means the 170 * length of the property won't overrun buf, and the unknown field is 1. 171 */ 172 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf, 173 DWORD size, DWORD propID) 174 { 175 const WINE_CERT_PROP_HEADER *ret = NULL; 176 BOOL done = FALSE; 177 178 while (size && !ret && !done) 179 { 180 if (size < sizeof(WINE_CERT_PROP_HEADER)) 181 { 182 SetLastError(CRYPT_E_FILE_ERROR); 183 done = TRUE; 184 } 185 else 186 { 187 const WINE_CERT_PROP_HEADER *hdr = 188 (const WINE_CERT_PROP_HEADER *)buf; 189 190 size -= sizeof(WINE_CERT_PROP_HEADER); 191 buf += sizeof(WINE_CERT_PROP_HEADER); 192 if (size < hdr->cb) 193 { 194 SetLastError(E_INVALIDARG); 195 done = TRUE; 196 } 197 else if (!hdr->propID) 198 { 199 /* assume a zero prop ID means the data are uninitialized, so 200 * stop looking. 201 */ 202 done = TRUE; 203 } 204 else if (hdr->unknown != 1) 205 { 206 SetLastError(ERROR_FILE_NOT_FOUND); 207 done = TRUE; 208 } 209 else if (hdr->propID == propID) 210 ret = hdr; 211 else 212 { 213 buf += hdr->cb; 214 size -= hdr->cb; 215 } 216 } 217 } 218 return ret; 219 } 220 221 static BOOL CRYPT_ReadContextProp( 222 const WINE_CONTEXT_INTERFACE *contextInterface, const void *context, 223 const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement) 224 { 225 BOOL ret; 226 227 if (cbElement < hdr->cb) 228 { 229 SetLastError(E_INVALIDARG); 230 ret = FALSE; 231 } 232 else if (hdr->unknown != 1) 233 { 234 SetLastError(ERROR_FILE_NOT_FOUND); 235 ret = FALSE; 236 } 237 else if (hdr->propID != CERT_CERT_PROP_ID && 238 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID) 239 { 240 /* Have to create a blob for most types, but not 241 * for all.. arghh. 242 */ 243 switch (hdr->propID) 244 { 245 case CERT_AUTO_ENROLL_PROP_ID: 246 case CERT_CTL_USAGE_PROP_ID: 247 case CERT_DESCRIPTION_PROP_ID: 248 case CERT_FRIENDLY_NAME_PROP_ID: 249 case CERT_HASH_PROP_ID: 250 case CERT_KEY_IDENTIFIER_PROP_ID: 251 case CERT_MD5_HASH_PROP_ID: 252 case CERT_NEXT_UPDATE_LOCATION_PROP_ID: 253 case CERT_PUBKEY_ALG_PARA_PROP_ID: 254 case CERT_PVK_FILE_PROP_ID: 255 case CERT_SIGNATURE_HASH_PROP_ID: 256 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: 257 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: 258 case CERT_ENROLLMENT_PROP_ID: 259 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: 260 case CERT_RENEWAL_PROP_ID: 261 { 262 CRYPT_DATA_BLOB blob = { hdr->cb, 263 (LPBYTE)pbElement }; 264 265 ret = contextInterface->setProp(context, 266 hdr->propID, 0, &blob); 267 break; 268 } 269 case CERT_DATE_STAMP_PROP_ID: 270 ret = contextInterface->setProp(context, 271 hdr->propID, 0, pbElement); 272 break; 273 case CERT_KEY_PROV_INFO_PROP_ID: 274 { 275 PCRYPT_KEY_PROV_INFO info = 276 (PCRYPT_KEY_PROV_INFO)pbElement; 277 278 CRYPT_FixKeyProvInfoPointers(info); 279 ret = contextInterface->setProp(context, 280 hdr->propID, 0, pbElement); 281 break; 282 } 283 default: 284 ret = FALSE; 285 } 286 } 287 else 288 { 289 /* ignore the context itself */ 290 ret = TRUE; 291 } 292 return ret; 293 } 294 295 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement, 296 DWORD dwContextTypeFlags, DWORD *pdwContentType) 297 { 298 const void *context; 299 300 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags, 301 pdwContentType); 302 303 if (!cbElement) 304 { 305 SetLastError(ERROR_END_OF_MEDIA); 306 return NULL; 307 } 308 309 __TRY 310 { 311 const WINE_CONTEXT_INTERFACE *contextInterface = NULL; 312 const WINE_CERT_PROP_HEADER *hdr = NULL; 313 DWORD type = 0; 314 BOOL ret; 315 316 ret = TRUE; 317 context = NULL; 318 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG) 319 { 320 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID); 321 if (hdr) 322 type = CERT_STORE_CERTIFICATE_CONTEXT; 323 else 324 { 325 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID); 326 if (hdr) 327 type = CERT_STORE_CRL_CONTEXT; 328 else 329 { 330 hdr = CRYPT_findPropID(pbElement, cbElement, 331 CERT_CTL_PROP_ID); 332 if (hdr) 333 type = CERT_STORE_CTL_CONTEXT; 334 } 335 } 336 } 337 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG) 338 { 339 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID); 340 type = CERT_STORE_CERTIFICATE_CONTEXT; 341 } 342 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG) 343 { 344 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID); 345 type = CERT_STORE_CRL_CONTEXT; 346 } 347 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG) 348 { 349 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID); 350 type = CERT_STORE_CTL_CONTEXT; 351 } 352 353 switch (type) 354 { 355 case CERT_STORE_CERTIFICATE_CONTEXT: 356 contextInterface = pCertInterface; 357 break; 358 case CERT_STORE_CRL_CONTEXT: 359 contextInterface = pCRLInterface; 360 break; 361 case CERT_STORE_CTL_CONTEXT: 362 contextInterface = pCTLInterface; 363 break; 364 default: 365 SetLastError(E_INVALIDARG); 366 ret = FALSE; 367 } 368 if (!hdr) 369 ret = FALSE; 370 371 if (ret) 372 context = contextInterface->create(X509_ASN_ENCODING, 373 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb); 374 if (ret && context) 375 { 376 BOOL noMoreProps = FALSE; 377 378 while (!noMoreProps && ret) 379 { 380 if (cbElement < sizeof(WINE_CERT_PROP_HEADER)) 381 ret = FALSE; 382 else 383 { 384 const WINE_CERT_PROP_HEADER *hdr = 385 (const WINE_CERT_PROP_HEADER *)pbElement; 386 387 TRACE("prop is %d\n", hdr->propID); 388 cbElement -= sizeof(WINE_CERT_PROP_HEADER); 389 pbElement += sizeof(WINE_CERT_PROP_HEADER); 390 if (!hdr->propID) 391 { 392 /* Like in CRYPT_findPropID, stop if the propID is zero 393 */ 394 noMoreProps = TRUE; 395 } 396 else 397 ret = CRYPT_ReadContextProp(contextInterface, context, 398 hdr, pbElement, cbElement); 399 pbElement += hdr->cb; 400 cbElement -= hdr->cb; 401 if (!cbElement) 402 noMoreProps = TRUE; 403 } 404 } 405 if (ret) 406 { 407 if (pdwContentType) 408 *pdwContentType = type; 409 } 410 else 411 { 412 Context_Release(context_from_ptr(context)); 413 context = NULL; 414 } 415 } 416 } 417 __EXCEPT_PAGE_FAULT 418 { 419 SetLastError(STATUS_ACCESS_VIOLATION); 420 context = NULL; 421 } 422 __ENDTRY 423 return context; 424 } 425 426 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' }; 427 428 typedef BOOL (*read_serialized_func)(void *handle, void *buffer, 429 DWORD bytesToRead, DWORD *bytesRead); 430 431 static BOOL CRYPT_ReadSerializedStore(void *handle, 432 read_serialized_func read_func, HCERTSTORE store) 433 { 434 BYTE fileHeaderBuf[sizeof(fileHeader)]; 435 DWORD read; 436 BOOL ret; 437 438 /* Failure reading is non-critical, we'll leave the store empty */ 439 ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read); 440 if (ret) 441 { 442 if (!read) 443 ; /* an empty file is okay */ 444 else if (read != sizeof(fileHeaderBuf)) 445 ret = FALSE; 446 else if (!memcmp(fileHeaderBuf, fileHeader, read)) 447 { 448 WINE_CERT_PROP_HEADER propHdr; 449 const void *context = NULL; 450 const WINE_CONTEXT_INTERFACE *contextInterface = NULL; 451 LPBYTE buf = NULL; 452 DWORD bufSize = 0; 453 454 do { 455 ret = read_func(handle, &propHdr, sizeof(propHdr), &read); 456 if (ret && read == sizeof(propHdr)) 457 { 458 if (contextInterface && context && 459 (propHdr.propID == CERT_CERT_PROP_ID || 460 propHdr.propID == CERT_CRL_PROP_ID || 461 propHdr.propID == CERT_CTL_PROP_ID)) 462 { 463 /* We have a new context, so free the existing one */ 464 Context_Release(context_from_ptr(context)); 465 } 466 if (propHdr.cb > bufSize) 467 { 468 /* Not reusing realloc, because the old data aren't 469 * needed any longer. 470 */ 471 CryptMemFree(buf); 472 buf = CryptMemAlloc(propHdr.cb); 473 bufSize = propHdr.cb; 474 } 475 if (!propHdr.cb) 476 ; /* Property is empty, nothing to do */ 477 else if (buf) 478 { 479 ret = read_func(handle, buf, propHdr.cb, &read); 480 if (ret && read == propHdr.cb) 481 { 482 if (propHdr.propID == CERT_CERT_PROP_ID) 483 { 484 contextInterface = pCertInterface; 485 ret = contextInterface->addEncodedToStore(store, 486 X509_ASN_ENCODING, buf, read, 487 CERT_STORE_ADD_NEW, &context); 488 } 489 else if (propHdr.propID == CERT_CRL_PROP_ID) 490 { 491 contextInterface = pCRLInterface; 492 ret = contextInterface->addEncodedToStore(store, 493 X509_ASN_ENCODING, buf, read, 494 CERT_STORE_ADD_NEW, &context); 495 } 496 else if (propHdr.propID == CERT_CTL_PROP_ID) 497 { 498 contextInterface = pCTLInterface; 499 ret = contextInterface->addEncodedToStore(store, 500 X509_ASN_ENCODING, buf, read, 501 CERT_STORE_ADD_NEW, &context); 502 } 503 else 504 { 505 if (!contextInterface) 506 { 507 WARN("prop id %d before a context id\n", 508 propHdr.propID); 509 ret = FALSE; 510 } 511 else 512 ret = CRYPT_ReadContextProp( 513 contextInterface, context, &propHdr, buf, 514 read); 515 } 516 } 517 } 518 else 519 ret = FALSE; 520 } 521 } while (ret && read > 0 && propHdr.cb); 522 if (contextInterface && context) 523 { 524 /* Free the last context added */ 525 Context_Release(context_from_ptr(context)); 526 } 527 CryptMemFree(buf); 528 ret = TRUE; 529 } 530 else 531 ret = FALSE; 532 } 533 else 534 ret = TRUE; 535 return ret; 536 } 537 538 static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead, 539 DWORD *bytesRead) 540 { 541 return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL); 542 } 543 544 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store) 545 { 546 return CRYPT_ReadSerializedStore(file, read_file_wrapper, store); 547 } 548 549 struct BlobReader 550 { 551 const CRYPT_DATA_BLOB *blob; 552 DWORD current; 553 }; 554 555 static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead, 556 DWORD *bytesRead) 557 { 558 struct BlobReader *reader = handle; 559 BOOL ret; 560 561 if (reader->current < reader->blob->cbData) 562 { 563 *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current); 564 memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead); 565 reader->current += *bytesRead; 566 ret = TRUE; 567 } 568 else if (reader->current == reader->blob->cbData) 569 { 570 *bytesRead = 0; 571 ret = TRUE; 572 } 573 else 574 ret = FALSE; 575 return ret; 576 } 577 578 BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob, 579 HCERTSTORE store) 580 { 581 struct BlobReader reader = { blob, 0 }; 582 583 return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store); 584 } 585 586 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext, 587 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) 588 { 589 return CRYPT_SerializeStoreElement(pCertContext, 590 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, 591 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement); 592 } 593 594 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext, 595 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) 596 { 597 return CRYPT_SerializeStoreElement(pCrlContext, 598 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded, 599 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement); 600 } 601 602 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext, 603 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement) 604 { 605 return CRYPT_SerializeStoreElement(pCtlContext, 606 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded, 607 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement); 608 } 609 610 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer, 611 DWORD size); 612 613 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output, 614 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store) 615 { 616 const void *context = NULL; 617 BOOL ret; 618 619 do { 620 context = contextInterface->enumContextsInStore(store, context); 621 if (context) 622 { 623 DWORD size = 0; 624 LPBYTE buf = NULL; 625 626 ret = contextInterface->serialize(context, 0, NULL, &size); 627 if (size) 628 buf = CryptMemAlloc(size); 629 if (buf) 630 { 631 ret = contextInterface->serialize(context, 0, buf, &size); 632 if (ret) 633 ret = output(handle, buf, size); 634 } 635 CryptMemFree(buf); 636 } 637 else 638 ret = TRUE; 639 } while (ret && context != NULL); 640 if (context) 641 Context_Release(context_from_ptr(context)); 642 return ret; 643 } 644 645 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store, 646 SerializedOutputFunc output, void *handle) 647 { 648 static const BYTE fileTrailer[12] = { 0 }; 649 WINE_CONTEXT_INTERFACE interface; 650 BOOL ret; 651 652 ret = output(handle, fileHeader, sizeof(fileHeader)); 653 if (ret) 654 { 655 interface = *pCertInterface; 656 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash; 657 ret = CRYPT_SerializeContextsToStream(output, handle, &interface, 658 store); 659 } 660 if (ret) 661 { 662 interface = *pCRLInterface; 663 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash; 664 ret = CRYPT_SerializeContextsToStream(output, handle, &interface, 665 store); 666 } 667 if (ret) 668 { 669 interface = *pCTLInterface; 670 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash; 671 ret = CRYPT_SerializeContextsToStream(output, handle, &interface, 672 store); 673 } 674 if (ret) 675 ret = output(handle, fileTrailer, sizeof(fileTrailer)); 676 return ret; 677 } 678 679 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size) 680 { 681 return WriteFile(handle, buffer, size, &size, NULL); 682 } 683 684 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store) 685 { 686 SetFilePointer(file, 0, NULL, FILE_BEGIN); 687 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc, 688 file); 689 } 690 691 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store, 692 DWORD dwMsgAndCertEncodingType, void *handle) 693 { 694 CERT_BLOB *blob = handle; 695 CRYPT_SIGNED_INFO signedInfo = { 0 }; 696 PCCERT_CONTEXT cert = NULL; 697 PCCRL_CONTEXT crl = NULL; 698 DWORD size; 699 BOOL ret = TRUE; 700 701 TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData); 702 703 do { 704 cert = CertEnumCertificatesInStore(store, cert); 705 if (cert) 706 signedInfo.cCertEncoded++; 707 } while (cert); 708 if (signedInfo.cCertEncoded) 709 { 710 signedInfo.rgCertEncoded = CryptMemAlloc( 711 signedInfo.cCertEncoded * sizeof(CERT_BLOB)); 712 if (!signedInfo.rgCertEncoded) 713 { 714 SetLastError(ERROR_OUTOFMEMORY); 715 ret = FALSE; 716 } 717 else 718 { 719 DWORD i = 0; 720 721 do { 722 cert = CertEnumCertificatesInStore(store, cert); 723 if (cert) 724 { 725 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded; 726 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded; 727 i++; 728 } 729 } while (cert); 730 } 731 } 732 733 do { 734 crl = CertEnumCRLsInStore(store, crl); 735 if (crl) 736 signedInfo.cCrlEncoded++; 737 } while (crl); 738 if (signedInfo.cCrlEncoded) 739 { 740 signedInfo.rgCrlEncoded = CryptMemAlloc( 741 signedInfo.cCrlEncoded * sizeof(CERT_BLOB)); 742 if (!signedInfo.rgCrlEncoded) 743 { 744 SetLastError(ERROR_OUTOFMEMORY); 745 ret = FALSE; 746 } 747 else 748 { 749 DWORD i = 0; 750 751 do { 752 crl = CertEnumCRLsInStore(store, crl); 753 if (crl) 754 { 755 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded; 756 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded; 757 i++; 758 } 759 } while (crl); 760 } 761 } 762 if (ret) 763 { 764 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size); 765 if (ret) 766 { 767 if (!blob->pbData) 768 blob->cbData = size; 769 else if (blob->cbData < size) 770 { 771 blob->cbData = size; 772 SetLastError(ERROR_MORE_DATA); 773 ret = FALSE; 774 } 775 else 776 { 777 blob->cbData = size; 778 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData, 779 &blob->cbData); 780 } 781 } 782 } 783 CryptMemFree(signedInfo.rgCertEncoded); 784 CryptMemFree(signedInfo.rgCrlEncoded); 785 TRACE("returning %d\n", ret); 786 return ret; 787 } 788 789 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store, 790 DWORD dwMsgAndCertEncodingType, void *handle) 791 { 792 CERT_BLOB blob = { 0, NULL }; 793 BOOL ret; 794 795 TRACE("(%p)\n", handle); 796 797 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob); 798 if (ret) 799 { 800 blob.pbData = CryptMemAlloc(blob.cbData); 801 if (blob.pbData) 802 { 803 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob); 804 if (ret) 805 ret = WriteFile(handle, blob.pbData, blob.cbData, 806 &blob.cbData, NULL); 807 } 808 else 809 { 810 SetLastError(ERROR_OUTOFMEMORY); 811 ret = FALSE; 812 } 813 } 814 TRACE("returning %d\n", ret); 815 return ret; 816 } 817 818 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store, 819 DWORD dwMsgAndCertEncodingType, void *handle) 820 { 821 return CRYPT_WriteSerializedStoreToFile(handle, store); 822 } 823 824 struct MemWrittenTracker 825 { 826 DWORD cbData; 827 BYTE *pbData; 828 DWORD written; 829 }; 830 831 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */ 832 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size) 833 { 834 struct MemWrittenTracker *tracker = handle; 835 BOOL ret; 836 837 if (tracker->written + size > tracker->cbData) 838 { 839 SetLastError(ERROR_MORE_DATA); 840 /* Update written so caller can notify its caller of the required size 841 */ 842 tracker->written += size; 843 ret = FALSE; 844 } 845 else 846 { 847 memcpy(tracker->pbData + tracker->written, buffer, size); 848 tracker->written += size; 849 ret = TRUE; 850 } 851 return ret; 852 } 853 854 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer, 855 DWORD size) 856 { 857 *(DWORD *)handle += size; 858 return TRUE; 859 } 860 861 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store, 862 DWORD dwMsgAndCertEncodingType, void *handle) 863 { 864 CERT_BLOB *blob = handle; 865 DWORD size = 0; 866 BOOL ret; 867 868 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes, 869 &size); 870 if (ret) 871 { 872 if (!blob->pbData) 873 blob->cbData = size; 874 else if (blob->cbData < size) 875 { 876 SetLastError(ERROR_MORE_DATA); 877 blob->cbData = size; 878 ret = FALSE; 879 } 880 else 881 { 882 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData, 883 0 }; 884 885 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc, 886 &tracker); 887 if (!ret && GetLastError() == ERROR_MORE_DATA) 888 blob->cbData = tracker.written; 889 } 890 } 891 TRACE("returning %d\n", ret); 892 return ret; 893 } 894 895 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType, 896 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags) 897 { 898 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *); 899 void *handle; 900 BOOL ret, closeFile = TRUE; 901 902 TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore, 903 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags); 904 905 switch (dwSaveAs) 906 { 907 case CERT_STORE_SAVE_AS_STORE: 908 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY) 909 saveFunc = CRYPT_SaveSerializedToMem; 910 else 911 saveFunc = CRYPT_SaveSerializedToFile; 912 break; 913 case CERT_STORE_SAVE_AS_PKCS7: 914 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY) 915 saveFunc = CRYPT_SavePKCSToMem; 916 else 917 saveFunc = CRYPT_SavePKCSToFile; 918 break; 919 default: 920 WARN("unimplemented for %d\n", dwSaveAs); 921 SetLastError(ERROR_INVALID_PARAMETER); 922 return FALSE; 923 } 924 switch (dwSaveTo) 925 { 926 case CERT_STORE_SAVE_TO_FILE: 927 handle = pvSaveToPara; 928 closeFile = FALSE; 929 break; 930 case CERT_STORE_SAVE_TO_FILENAME_A: 931 handle = CreateFileA(pvSaveToPara, GENERIC_WRITE, 0, NULL, 932 CREATE_ALWAYS, 0, NULL); 933 break; 934 case CERT_STORE_SAVE_TO_FILENAME_W: 935 handle = CreateFileW(pvSaveToPara, GENERIC_WRITE, 0, NULL, 936 CREATE_ALWAYS, 0, NULL); 937 break; 938 case CERT_STORE_SAVE_TO_MEMORY: 939 handle = pvSaveToPara; 940 break; 941 default: 942 WARN("unimplemented for %d\n", dwSaveTo); 943 SetLastError(ERROR_INVALID_PARAMETER); 944 return FALSE; 945 } 946 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle); 947 if (closeFile) 948 CloseHandle(handle); 949 TRACE("returning %d\n", ret); 950 return ret; 951 } 952 953 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore, 954 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags, 955 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext) 956 { 957 const void *context; 958 DWORD type; 959 BOOL ret; 960 961 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore, 962 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags, 963 pdwContentType, ppvContext); 964 965 /* Call the internal function, then delete the hashes. Tests show this 966 * function uses real hash values, not whatever's stored in the hash 967 * property. 968 */ 969 context = CRYPT_ReadSerializedElement(pbElement, cbElement, 970 dwContextTypeFlags, &type); 971 if (context) 972 { 973 const WINE_CONTEXT_INTERFACE *contextInterface = NULL; 974 975 switch (type) 976 { 977 case CERT_STORE_CERTIFICATE_CONTEXT: 978 contextInterface = pCertInterface; 979 break; 980 case CERT_STORE_CRL_CONTEXT: 981 contextInterface = pCRLInterface; 982 break; 983 case CERT_STORE_CTL_CONTEXT: 984 contextInterface = pCTLInterface; 985 break; 986 default: 987 SetLastError(E_INVALIDARG); 988 } 989 if (contextInterface) 990 { 991 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL); 992 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL); 993 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0, 994 NULL); 995 if (pdwContentType) 996 *pdwContentType = type; 997 ret = contextInterface->addContextToStore(hCertStore, context, 998 dwAddDisposition, ppvContext); 999 Context_Release(context_from_ptr(context)); 1000 } 1001 else 1002 ret = FALSE; 1003 } 1004 else 1005 ret = FALSE; 1006 return ret; 1007 } 1008