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