1 /* 2 * Copyright 2008 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 20 #include <assert.h> 21 #include <stdarg.h> 22 23 #include "windef.h" 24 #include "winbase.h" 25 #include "wincrypt.h" 26 #include "wine/debug.h" 27 #include "crypt32_private.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(crypt); 30 31 static void CTL_free(context_t *context) 32 { 33 ctl_t *ctl = (ctl_t*)context; 34 35 CryptMsgClose(ctl->ctx.hCryptMsg); 36 CryptMemFree(ctl->ctx.pbCtlEncoded); 37 CryptMemFree(ctl->ctx.pbCtlContext); 38 LocalFree(ctl->ctx.pCtlInfo); 39 } 40 41 static context_t *CTL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link) 42 { 43 ctl_t *ctl; 44 45 if(!use_link) { 46 FIXME("Only links supported\n"); 47 return NULL; 48 } 49 50 ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context, store); 51 if(!ctl) 52 return NULL; 53 54 ctl->ctx.hCertStore = store; 55 return &ctl->base; 56 } 57 58 static const context_vtbl_t ctl_vtbl = { 59 CTL_free, 60 CTL_clone 61 }; 62 63 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore, 64 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition, 65 PCCTL_CONTEXT* ppStoreContext) 66 { 67 WINECRYPT_CERTSTORE *store = hCertStore; 68 BOOL ret = TRUE; 69 PCCTL_CONTEXT toAdd = NULL, existing = NULL; 70 71 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition, 72 ppStoreContext); 73 74 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS) 75 { 76 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING, 77 pCtlContext, NULL); 78 } 79 80 switch (dwAddDisposition) 81 { 82 case CERT_STORE_ADD_ALWAYS: 83 toAdd = CertDuplicateCTLContext(pCtlContext); 84 break; 85 case CERT_STORE_ADD_NEW: 86 if (existing) 87 { 88 TRACE("found matching CTL, not adding\n"); 89 SetLastError(CRYPT_E_EXISTS); 90 ret = FALSE; 91 } 92 else 93 toAdd = CertDuplicateCTLContext(pCtlContext); 94 break; 95 case CERT_STORE_ADD_NEWER: 96 if (existing) 97 { 98 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate, 99 &pCtlContext->pCtlInfo->ThisUpdate); 100 101 if (newer < 0) 102 toAdd = CertDuplicateCTLContext(pCtlContext); 103 else 104 { 105 TRACE("existing CTL is newer, not adding\n"); 106 SetLastError(CRYPT_E_EXISTS); 107 ret = FALSE; 108 } 109 } 110 else 111 toAdd = CertDuplicateCTLContext(pCtlContext); 112 break; 113 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: 114 if (existing) 115 { 116 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate, 117 &pCtlContext->pCtlInfo->ThisUpdate); 118 119 if (newer < 0) 120 { 121 toAdd = CertDuplicateCTLContext(pCtlContext); 122 Context_CopyProperties(existing, pCtlContext); 123 } 124 else 125 { 126 TRACE("existing CTL is newer, not adding\n"); 127 SetLastError(CRYPT_E_EXISTS); 128 ret = FALSE; 129 } 130 } 131 else 132 toAdd = CertDuplicateCTLContext(pCtlContext); 133 break; 134 case CERT_STORE_ADD_REPLACE_EXISTING: 135 toAdd = CertDuplicateCTLContext(pCtlContext); 136 break; 137 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: 138 toAdd = CertDuplicateCTLContext(pCtlContext); 139 if (existing) 140 Context_CopyProperties(toAdd, existing); 141 break; 142 case CERT_STORE_ADD_USE_EXISTING: 143 if (existing) 144 { 145 Context_CopyProperties(existing, pCtlContext); 146 if (ppStoreContext) 147 *ppStoreContext = CertDuplicateCTLContext(existing); 148 } 149 else 150 toAdd = CertDuplicateCTLContext(pCtlContext); 151 break; 152 default: 153 FIXME("Unimplemented add disposition %d\n", dwAddDisposition); 154 ret = FALSE; 155 } 156 157 if (toAdd) 158 { 159 if (store) { 160 context_t *ret_ctx; 161 162 ret = store->vtbl->ctls.addContext(store, context_from_ptr(toAdd), 163 existing ? context_from_ptr(existing) : NULL, ppStoreContext ? &ret_ctx : NULL, TRUE); 164 if(ret && ppStoreContext) 165 *ppStoreContext = context_ptr(ret_ctx); 166 }else if (ppStoreContext) { 167 *ppStoreContext = CertDuplicateCTLContext(toAdd); 168 } 169 CertFreeCTLContext(toAdd); 170 } 171 CertFreeCTLContext(existing); 172 173 TRACE("returning %d\n", ret); 174 return ret; 175 } 176 177 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore, 178 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded, 179 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext) 180 { 181 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType, 182 pbCtlEncoded, cbCtlEncoded); 183 BOOL ret; 184 185 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, 186 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition, 187 ppCtlContext); 188 189 if (ctl) 190 { 191 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition, 192 ppCtlContext); 193 CertFreeCTLContext(ctl); 194 } 195 else 196 ret = FALSE; 197 return ret; 198 } 199 200 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore, PCCTL_CONTEXT pPrev) 201 { 202 ctl_t *prev = pPrev ? ctl_from_ptr(pPrev) : NULL, *ret; 203 WINECRYPT_CERTSTORE *hcs = hCertStore; 204 205 TRACE("(%p, %p)\n", hCertStore, pPrev); 206 if (!hCertStore) 207 ret = NULL; 208 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) 209 ret = NULL; 210 else 211 ret = (ctl_t*)hcs->vtbl->ctls.enumContext(hcs, prev ? &prev->base : NULL); 212 return ret ? &ret->ctx : NULL; 213 } 214 215 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType, 216 DWORD dwFlags, const void *pvPara); 217 218 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType, 219 DWORD dwFlags, const void *pvPara) 220 { 221 return TRUE; 222 } 223 224 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType, 225 DWORD dwFlags, const void *pvPara) 226 { 227 BOOL ret; 228 BYTE hash[16]; 229 DWORD size = sizeof(hash); 230 231 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash, 232 &size); 233 if (ret) 234 { 235 const CRYPT_HASH_BLOB *pHash = pvPara; 236 237 if (size == pHash->cbData) 238 ret = !memcmp(pHash->pbData, hash, size); 239 else 240 ret = FALSE; 241 } 242 return ret; 243 } 244 245 static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType, 246 DWORD dwFlags, const void *pvPara) 247 { 248 BOOL ret; 249 BYTE hash[20]; 250 DWORD size = sizeof(hash); 251 252 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash, 253 &size); 254 if (ret) 255 { 256 const CRYPT_HASH_BLOB *pHash = pvPara; 257 258 if (size == pHash->cbData) 259 ret = !memcmp(pHash->pbData, hash, size); 260 else 261 ret = FALSE; 262 } 263 return ret; 264 } 265 266 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType, 267 DWORD dwFlags, const void *pvPara) 268 { 269 BOOL ret; 270 271 if (pvPara) 272 { 273 PCCTL_CONTEXT ctl = pvPara; 274 275 if (pCtlContext->cbCtlContext == ctl->cbCtlContext) 276 { 277 if (ctl->cbCtlContext) 278 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext, 279 ctl->cbCtlContext); 280 else 281 ret = TRUE; 282 } 283 else 284 ret = FALSE; 285 } 286 else 287 ret = FALSE; 288 return ret; 289 } 290 291 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore, 292 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType, 293 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext) 294 { 295 PCCTL_CONTEXT ret; 296 CtlCompareFunc compare; 297 298 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType, 299 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext); 300 301 switch (dwFindType) 302 { 303 case CTL_FIND_ANY: 304 compare = compare_ctl_any; 305 break; 306 case CTL_FIND_SHA1_HASH: 307 compare = compare_ctl_by_sha1_hash; 308 break; 309 case CTL_FIND_MD5_HASH: 310 compare = compare_ctl_by_md5_hash; 311 break; 312 case CTL_FIND_EXISTING: 313 compare = compare_ctl_existing; 314 break; 315 default: 316 FIXME("find type %08x unimplemented\n", dwFindType); 317 compare = NULL; 318 } 319 320 if (compare) 321 { 322 BOOL matches = FALSE; 323 324 ret = pPrevCtlContext; 325 do { 326 ret = CertEnumCTLsInStore(hCertStore, ret); 327 if (ret) 328 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara); 329 } while (ret != NULL && !matches); 330 if (!ret) 331 SetLastError(CRYPT_E_NOT_FOUND); 332 } 333 else 334 { 335 SetLastError(CRYPT_E_NOT_FOUND); 336 ret = NULL; 337 } 338 return ret; 339 } 340 341 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext) 342 { 343 WINECRYPT_CERTSTORE *hcs; 344 ctl_t *ctl = ctl_from_ptr(pCtlContext); 345 BOOL ret; 346 347 TRACE("(%p)\n", pCtlContext); 348 349 if (!pCtlContext) 350 return TRUE; 351 352 hcs = pCtlContext->hCertStore; 353 354 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC) 355 return FALSE; 356 357 ret = hcs->vtbl->ctls.delete(hcs, &ctl->base); 358 if (ret) 359 ret = CertFreeCTLContext(pCtlContext); 360 return ret; 361 } 362 363 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType, 364 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded) 365 { 366 ctl_t *ctl = NULL; 367 HCRYPTMSG msg; 368 BOOL ret; 369 BYTE *content = NULL; 370 DWORD contentSize = 0, size; 371 PCTL_INFO ctlInfo = NULL; 372 373 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded, 374 cbCtlEncoded); 375 376 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING) 377 { 378 SetLastError(E_INVALIDARG); 379 return NULL; 380 } 381 if (!pbCtlEncoded || !cbCtlEncoded) 382 { 383 SetLastError(ERROR_INVALID_DATA); 384 return NULL; 385 } 386 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0, 387 0, NULL, NULL); 388 if (!msg) 389 return NULL; 390 ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE); 391 if (!ret) 392 { 393 SetLastError(ERROR_INVALID_DATA); 394 goto end; 395 } 396 /* Check that it's really a CTL */ 397 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size); 398 if (ret) 399 { 400 char *innerContent = CryptMemAlloc(size); 401 402 if (innerContent) 403 { 404 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, 405 innerContent, &size); 406 if (ret) 407 { 408 if (strcmp(innerContent, szOID_CTL)) 409 { 410 SetLastError(ERROR_INVALID_DATA); 411 ret = FALSE; 412 } 413 } 414 CryptMemFree(innerContent); 415 } 416 else 417 { 418 SetLastError(ERROR_OUTOFMEMORY); 419 ret = FALSE; 420 } 421 } 422 if (!ret) 423 goto end; 424 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize); 425 if (!ret) 426 goto end; 427 content = CryptMemAlloc(contentSize); 428 if (content) 429 { 430 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content, 431 &contentSize); 432 if (ret) 433 { 434 ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL, 435 content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL, 436 &ctlInfo, &size); 437 if (ret) 438 { 439 ctl = (ctl_t*)Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl, &empty_store); 440 if (ctl) 441 { 442 BYTE *data = CryptMemAlloc(cbCtlEncoded); 443 444 if (data) 445 { 446 memcpy(data, pbCtlEncoded, cbCtlEncoded); 447 ctl->ctx.dwMsgAndCertEncodingType = 448 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; 449 ctl->ctx.pbCtlEncoded = data; 450 ctl->ctx.cbCtlEncoded = cbCtlEncoded; 451 ctl->ctx.pCtlInfo = ctlInfo; 452 ctl->ctx.hCertStore = &empty_store; 453 ctl->ctx.hCryptMsg = msg; 454 ctl->ctx.pbCtlContext = content; 455 ctl->ctx.cbCtlContext = contentSize; 456 } 457 else 458 { 459 SetLastError(ERROR_OUTOFMEMORY); 460 ret = FALSE; 461 } 462 } 463 else 464 { 465 SetLastError(ERROR_OUTOFMEMORY); 466 ret = FALSE; 467 } 468 } 469 } 470 } 471 else 472 { 473 SetLastError(ERROR_OUTOFMEMORY); 474 ret = FALSE; 475 } 476 477 end: 478 if (!ret) 479 { 480 if(ctl) 481 Context_Release(&ctl->base); 482 ctl = NULL; 483 LocalFree(ctlInfo); 484 CryptMemFree(content); 485 CryptMsgClose(msg); 486 return NULL; 487 } 488 return &ctl->ctx; 489 } 490 491 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext) 492 { 493 TRACE("(%p)\n", pCtlContext); 494 if (pCtlContext) 495 Context_AddRef(&ctl_from_ptr(pCtlContext)->base); 496 return pCtlContext; 497 } 498 499 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext) 500 { 501 TRACE("(%p)\n", pCTLContext); 502 503 if (pCTLContext) 504 Context_Release(&ctl_from_ptr(pCTLContext)->base); 505 return TRUE; 506 } 507 508 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext, 509 DWORD dwPropId) 510 { 511 ctl_t *ctl = ctl_from_ptr(pCTLContext); 512 DWORD ret; 513 514 TRACE("(%p, %d)\n", pCTLContext, dwPropId); 515 516 if (ctl->base.properties) 517 ret = ContextPropertyList_EnumPropIDs(ctl->base.properties, dwPropId); 518 else 519 ret = 0; 520 return ret; 521 } 522 523 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId, 524 DWORD dwFlags, const void *pvData); 525 526 static BOOL CTLContext_GetHashProp(ctl_t *ctl, DWORD dwPropId, 527 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData, 528 DWORD *pcbData) 529 { 530 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData, 531 pcbData); 532 if (ret && pvData) 533 { 534 CRYPT_DATA_BLOB blob = { *pcbData, pvData }; 535 536 ret = CTLContext_SetProperty(ctl, dwPropId, 0, &blob); 537 } 538 return ret; 539 } 540 541 static BOOL CTLContext_GetProperty(ctl_t *ctl, DWORD dwPropId, 542 void *pvData, DWORD *pcbData) 543 { 544 BOOL ret; 545 CRYPT_DATA_BLOB blob; 546 547 TRACE("(%p, %d, %p, %p)\n", ctl, dwPropId, pvData, pcbData); 548 549 if (ctl->base.properties) 550 ret = ContextPropertyList_FindProperty(ctl->base.properties, dwPropId, &blob); 551 else 552 ret = FALSE; 553 if (ret) 554 { 555 if (!pvData) 556 *pcbData = blob.cbData; 557 else if (*pcbData < blob.cbData) 558 { 559 SetLastError(ERROR_MORE_DATA); 560 *pcbData = blob.cbData; 561 ret = FALSE; 562 } 563 else 564 { 565 memcpy(pvData, blob.pbData, blob.cbData); 566 *pcbData = blob.cbData; 567 } 568 } 569 else 570 { 571 /* Implicit properties */ 572 switch (dwPropId) 573 { 574 case CERT_SHA1_HASH_PROP_ID: 575 ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_SHA1, 576 ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData); 577 break; 578 case CERT_MD5_HASH_PROP_ID: 579 ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_MD5, 580 ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData); 581 break; 582 default: 583 SetLastError(CRYPT_E_NOT_FOUND); 584 } 585 } 586 TRACE("returning %d\n", ret); 587 return ret; 588 } 589 590 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext, 591 DWORD dwPropId, void *pvData, DWORD *pcbData) 592 { 593 BOOL ret; 594 595 TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData); 596 597 switch (dwPropId) 598 { 599 case 0: 600 case CERT_CERT_PROP_ID: 601 case CERT_CRL_PROP_ID: 602 case CERT_CTL_PROP_ID: 603 SetLastError(E_INVALIDARG); 604 ret = FALSE; 605 break; 606 case CERT_ACCESS_STATE_PROP_ID: 607 if (!pvData) 608 { 609 *pcbData = sizeof(DWORD); 610 ret = TRUE; 611 } 612 else if (*pcbData < sizeof(DWORD)) 613 { 614 SetLastError(ERROR_MORE_DATA); 615 *pcbData = sizeof(DWORD); 616 ret = FALSE; 617 } 618 else 619 { 620 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId, pvData, pcbData); 621 } 622 break; 623 default: 624 ret = CTLContext_GetProperty(ctl_from_ptr(pCTLContext), dwPropId, pvData, 625 pcbData); 626 } 627 return ret; 628 } 629 630 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId, 631 DWORD dwFlags, const void *pvData) 632 { 633 BOOL ret; 634 635 TRACE("(%p, %d, %08x, %p)\n", ctl, dwPropId, dwFlags, pvData); 636 637 if (!ctl->base.properties) 638 ret = FALSE; 639 else if (!pvData) 640 { 641 ContextPropertyList_RemoveProperty(ctl->base.properties, dwPropId); 642 ret = TRUE; 643 } 644 else 645 { 646 switch (dwPropId) 647 { 648 case CERT_AUTO_ENROLL_PROP_ID: 649 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */ 650 case CERT_DESCRIPTION_PROP_ID: 651 case CERT_FRIENDLY_NAME_PROP_ID: 652 case CERT_HASH_PROP_ID: 653 case CERT_KEY_IDENTIFIER_PROP_ID: 654 case CERT_MD5_HASH_PROP_ID: 655 case CERT_NEXT_UPDATE_LOCATION_PROP_ID: 656 case CERT_PUBKEY_ALG_PARA_PROP_ID: 657 case CERT_PVK_FILE_PROP_ID: 658 case CERT_SIGNATURE_HASH_PROP_ID: 659 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: 660 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: 661 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: 662 case CERT_ENROLLMENT_PROP_ID: 663 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID: 664 case CERT_RENEWAL_PROP_ID: 665 { 666 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData; 667 668 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId, 669 blob->pbData, blob->cbData); 670 break; 671 } 672 case CERT_DATE_STAMP_PROP_ID: 673 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId, 674 pvData, sizeof(FILETIME)); 675 break; 676 default: 677 FIXME("%d: stub\n", dwPropId); 678 ret = FALSE; 679 } 680 } 681 TRACE("returning %d\n", ret); 682 return ret; 683 } 684 685 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext, 686 DWORD dwPropId, DWORD dwFlags, const void *pvData) 687 { 688 BOOL ret; 689 690 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData); 691 692 /* Handle special cases for "read-only"/invalid prop IDs. Windows just 693 * crashes on most of these, I'll be safer. 694 */ 695 switch (dwPropId) 696 { 697 case 0: 698 case CERT_ACCESS_STATE_PROP_ID: 699 case CERT_CERT_PROP_ID: 700 case CERT_CRL_PROP_ID: 701 case CERT_CTL_PROP_ID: 702 SetLastError(E_INVALIDARG); 703 return FALSE; 704 } 705 ret = CTLContext_SetProperty(ctl_from_ptr(pCTLContext), dwPropId, dwFlags, pvData); 706 TRACE("returning %d\n", ret); 707 return ret; 708 } 709