configure: Add a check for sys/ucontext.h and include it where appropriate.
[wine.git] / dlls / crypt32 / ctl.c
blobc18e608a9761e1b75fd9c9e3868580c39bbd74bb
1 /*
2 * Copyright 2008 Juan Lang
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.
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.
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
20 #include <assert.h>
21 #include <stdarg.h>
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"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 static void CTL_free(context_t *context)
34 ctl_t *ctl = (ctl_t*)context;
36 CryptMsgClose(ctl->ctx.hCryptMsg);
37 CryptMemFree(ctl->ctx.pbCtlEncoded);
38 CryptMemFree(ctl->ctx.pbCtlContext);
39 LocalFree(ctl->ctx.pCtlInfo);
42 static context_t *CTL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
44 ctl_t *ctl;
46 if(!use_link) {
47 FIXME("Only links supported\n");
48 return NULL;
51 ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context, store);
52 if(!ctl)
53 return NULL;
55 ctl->ctx.hCertStore = store;
56 return &ctl->base;
59 static const context_vtbl_t ctl_vtbl = {
60 CTL_free,
61 CTL_clone
64 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
65 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
66 PCCTL_CONTEXT* ppStoreContext)
68 WINECRYPT_CERTSTORE *store = hCertStore;
69 BOOL ret = TRUE;
70 PCCTL_CONTEXT toAdd = NULL, existing = NULL;
72 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
73 ppStoreContext);
75 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
77 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
78 pCtlContext, NULL);
81 switch (dwAddDisposition)
83 case CERT_STORE_ADD_ALWAYS:
84 toAdd = CertDuplicateCTLContext(pCtlContext);
85 break;
86 case CERT_STORE_ADD_NEW:
87 if (existing)
89 TRACE("found matching CTL, not adding\n");
90 SetLastError(CRYPT_E_EXISTS);
91 ret = FALSE;
93 else
94 toAdd = CertDuplicateCTLContext(pCtlContext);
95 break;
96 case CERT_STORE_ADD_NEWER:
97 if (existing)
99 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
100 &pCtlContext->pCtlInfo->ThisUpdate);
102 if (newer < 0)
103 toAdd = CertDuplicateCTLContext(pCtlContext);
104 else
106 TRACE("existing CTL is newer, not adding\n");
107 SetLastError(CRYPT_E_EXISTS);
108 ret = FALSE;
111 else
112 toAdd = CertDuplicateCTLContext(pCtlContext);
113 break;
114 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
115 if (existing)
117 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
118 &pCtlContext->pCtlInfo->ThisUpdate);
120 if (newer < 0)
122 toAdd = CertDuplicateCTLContext(pCtlContext);
123 Context_CopyProperties(existing, pCtlContext);
125 else
127 TRACE("existing CTL is newer, not adding\n");
128 SetLastError(CRYPT_E_EXISTS);
129 ret = FALSE;
132 else
133 toAdd = CertDuplicateCTLContext(pCtlContext);
134 break;
135 case CERT_STORE_ADD_REPLACE_EXISTING:
136 toAdd = CertDuplicateCTLContext(pCtlContext);
137 break;
138 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
139 toAdd = CertDuplicateCTLContext(pCtlContext);
140 if (existing)
141 Context_CopyProperties(toAdd, existing);
142 break;
143 case CERT_STORE_ADD_USE_EXISTING:
144 if (existing)
146 Context_CopyProperties(existing, pCtlContext);
147 if (ppStoreContext)
148 *ppStoreContext = CertDuplicateCTLContext(existing);
150 else
151 toAdd = CertDuplicateCTLContext(pCtlContext);
152 break;
153 default:
154 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
155 ret = FALSE;
158 if (toAdd)
160 if (store) {
161 context_t *ret_ctx;
163 ret = store->vtbl->ctls.addContext(store, context_from_ptr(toAdd),
164 existing ? context_from_ptr(existing) : NULL, ppStoreContext ? &ret_ctx : NULL, TRUE);
165 if(ret && ppStoreContext)
166 *ppStoreContext = context_ptr(ret_ctx);
167 }else if (ppStoreContext) {
168 *ppStoreContext = CertDuplicateCTLContext(toAdd);
170 CertFreeCTLContext(toAdd);
172 CertFreeCTLContext(existing);
174 TRACE("returning %d\n", ret);
175 return ret;
178 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
179 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
180 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
182 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
183 pbCtlEncoded, cbCtlEncoded);
184 BOOL ret;
186 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
187 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
188 ppCtlContext);
190 if (ctl)
192 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
193 ppCtlContext);
194 CertFreeCTLContext(ctl);
196 else
197 ret = FALSE;
198 return ret;
201 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore, PCCTL_CONTEXT pPrev)
203 ctl_t *prev = pPrev ? ctl_from_ptr(pPrev) : NULL, *ret;
204 WINECRYPT_CERTSTORE *hcs = hCertStore;
206 TRACE("(%p, %p)\n", hCertStore, pPrev);
207 if (!hCertStore)
208 ret = NULL;
209 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
210 ret = NULL;
211 else
212 ret = (ctl_t*)hcs->vtbl->ctls.enumContext(hcs, prev ? &prev->base : NULL);
213 return ret ? &ret->ctx : NULL;
216 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
217 DWORD dwFlags, const void *pvPara);
219 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
220 DWORD dwFlags, const void *pvPara)
222 return TRUE;
225 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
226 DWORD dwFlags, const void *pvPara)
228 BOOL ret;
229 BYTE hash[16];
230 DWORD size = sizeof(hash);
232 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash,
233 &size);
234 if (ret)
236 const CRYPT_HASH_BLOB *pHash = pvPara;
238 if (size == pHash->cbData)
239 ret = !memcmp(pHash->pbData, hash, size);
240 else
241 ret = FALSE;
243 return ret;
246 static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
247 DWORD dwFlags, const void *pvPara)
249 BOOL ret;
250 BYTE hash[20];
251 DWORD size = sizeof(hash);
253 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
254 &size);
255 if (ret)
257 const CRYPT_HASH_BLOB *pHash = pvPara;
259 if (size == pHash->cbData)
260 ret = !memcmp(pHash->pbData, hash, size);
261 else
262 ret = FALSE;
264 return ret;
267 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
268 DWORD dwFlags, const void *pvPara)
270 BOOL ret;
272 if (pvPara)
274 PCCTL_CONTEXT ctl = pvPara;
276 if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
278 if (ctl->cbCtlContext)
279 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
280 ctl->cbCtlContext);
281 else
282 ret = TRUE;
284 else
285 ret = FALSE;
287 else
288 ret = FALSE;
289 return ret;
292 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
293 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
294 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
296 PCCTL_CONTEXT ret;
297 CtlCompareFunc compare;
299 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
300 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
302 switch (dwFindType)
304 case CTL_FIND_ANY:
305 compare = compare_ctl_any;
306 break;
307 case CTL_FIND_SHA1_HASH:
308 compare = compare_ctl_by_sha1_hash;
309 break;
310 case CTL_FIND_MD5_HASH:
311 compare = compare_ctl_by_md5_hash;
312 break;
313 case CTL_FIND_EXISTING:
314 compare = compare_ctl_existing;
315 break;
316 default:
317 FIXME("find type %08x unimplemented\n", dwFindType);
318 compare = NULL;
321 if (compare)
323 BOOL matches = FALSE;
325 ret = pPrevCtlContext;
326 do {
327 ret = CertEnumCTLsInStore(hCertStore, ret);
328 if (ret)
329 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
330 } while (ret != NULL && !matches);
331 if (!ret)
332 SetLastError(CRYPT_E_NOT_FOUND);
334 else
336 SetLastError(CRYPT_E_NOT_FOUND);
337 ret = NULL;
339 return ret;
342 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
344 WINECRYPT_CERTSTORE *hcs;
345 ctl_t *ctl = ctl_from_ptr(pCtlContext);
346 BOOL ret;
348 TRACE("(%p)\n", pCtlContext);
350 if (!pCtlContext)
351 return TRUE;
353 hcs = pCtlContext->hCertStore;
355 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
356 return FALSE;
358 ret = hcs->vtbl->ctls.delete(hcs, &ctl->base);
359 if (ret)
360 ret = CertFreeCTLContext(pCtlContext);
361 return ret;
364 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
365 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
367 ctl_t *ctl = NULL;
368 HCRYPTMSG msg;
369 BOOL ret;
370 BYTE *content = NULL;
371 DWORD contentSize = 0, size;
372 PCTL_INFO ctlInfo = NULL;
374 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded,
375 cbCtlEncoded);
377 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING)
379 SetLastError(E_INVALIDARG);
380 return NULL;
382 if (!pbCtlEncoded || !cbCtlEncoded)
384 SetLastError(ERROR_INVALID_DATA);
385 return NULL;
387 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0,
388 0, NULL, NULL);
389 if (!msg)
390 return NULL;
391 ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE);
392 if (!ret)
394 SetLastError(ERROR_INVALID_DATA);
395 goto end;
397 /* Check that it's really a CTL */
398 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size);
399 if (ret)
401 char *innerContent = CryptMemAlloc(size);
403 if (innerContent)
405 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0,
406 innerContent, &size);
407 if (ret)
409 if (strcmp(innerContent, szOID_CTL))
411 SetLastError(ERROR_INVALID_DATA);
412 ret = FALSE;
415 CryptMemFree(innerContent);
417 else
419 SetLastError(ERROR_OUTOFMEMORY);
420 ret = FALSE;
423 if (!ret)
424 goto end;
425 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize);
426 if (!ret)
427 goto end;
428 content = CryptMemAlloc(contentSize);
429 if (content)
431 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content,
432 &contentSize);
433 if (ret)
435 ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL,
436 content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL,
437 &ctlInfo, &size);
438 if (ret)
440 ctl = (ctl_t*)Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl, &empty_store);
441 if (ctl)
443 BYTE *data = CryptMemAlloc(cbCtlEncoded);
445 if (data)
447 memcpy(data, pbCtlEncoded, cbCtlEncoded);
448 ctl->ctx.dwMsgAndCertEncodingType =
449 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
450 ctl->ctx.pbCtlEncoded = data;
451 ctl->ctx.cbCtlEncoded = cbCtlEncoded;
452 ctl->ctx.pCtlInfo = ctlInfo;
453 ctl->ctx.hCertStore = &empty_store;
454 ctl->ctx.hCryptMsg = msg;
455 ctl->ctx.pbCtlContext = content;
456 ctl->ctx.cbCtlContext = contentSize;
458 else
460 SetLastError(ERROR_OUTOFMEMORY);
461 ret = FALSE;
464 else
466 SetLastError(ERROR_OUTOFMEMORY);
467 ret = FALSE;
472 else
474 SetLastError(ERROR_OUTOFMEMORY);
475 ret = FALSE;
478 end:
479 if (!ret)
481 if(ctl)
482 Context_Release(&ctl->base);
483 ctl = NULL;
484 LocalFree(ctlInfo);
485 CryptMemFree(content);
486 CryptMsgClose(msg);
487 return NULL;
489 return &ctl->ctx;
492 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
494 TRACE("(%p)\n", pCtlContext);
495 if (pCtlContext)
496 Context_AddRef(&ctl_from_ptr(pCtlContext)->base);
497 return pCtlContext;
500 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
502 TRACE("(%p)\n", pCTLContext);
504 if (pCTLContext)
505 Context_Release(&ctl_from_ptr(pCTLContext)->base);
506 return TRUE;
509 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
510 DWORD dwPropId)
512 ctl_t *ctl = ctl_from_ptr(pCTLContext);
513 DWORD ret;
515 TRACE("(%p, %d)\n", pCTLContext, dwPropId);
517 if (ctl->base.properties)
518 ret = ContextPropertyList_EnumPropIDs(ctl->base.properties, dwPropId);
519 else
520 ret = 0;
521 return ret;
524 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
525 DWORD dwFlags, const void *pvData);
527 static BOOL CTLContext_GetHashProp(ctl_t *ctl, DWORD dwPropId,
528 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
529 DWORD *pcbData)
531 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
532 pcbData);
533 if (ret && pvData)
535 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
537 ret = CTLContext_SetProperty(ctl, dwPropId, 0, &blob);
539 return ret;
542 static BOOL CTLContext_GetProperty(ctl_t *ctl, DWORD dwPropId,
543 void *pvData, DWORD *pcbData)
545 BOOL ret;
546 CRYPT_DATA_BLOB blob;
548 TRACE("(%p, %d, %p, %p)\n", ctl, dwPropId, pvData, pcbData);
550 if (ctl->base.properties)
551 ret = ContextPropertyList_FindProperty(ctl->base.properties, dwPropId, &blob);
552 else
553 ret = FALSE;
554 if (ret)
556 if (!pvData)
557 *pcbData = blob.cbData;
558 else if (*pcbData < blob.cbData)
560 SetLastError(ERROR_MORE_DATA);
561 *pcbData = blob.cbData;
562 ret = FALSE;
564 else
566 memcpy(pvData, blob.pbData, blob.cbData);
567 *pcbData = blob.cbData;
570 else
572 /* Implicit properties */
573 switch (dwPropId)
575 case CERT_SHA1_HASH_PROP_ID:
576 ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_SHA1,
577 ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData);
578 break;
579 case CERT_MD5_HASH_PROP_ID:
580 ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_MD5,
581 ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData);
582 break;
583 default:
584 SetLastError(CRYPT_E_NOT_FOUND);
587 TRACE("returning %d\n", ret);
588 return ret;
591 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
592 DWORD dwPropId, void *pvData, DWORD *pcbData)
594 BOOL ret;
596 TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData);
598 switch (dwPropId)
600 case 0:
601 case CERT_CERT_PROP_ID:
602 case CERT_CRL_PROP_ID:
603 case CERT_CTL_PROP_ID:
604 SetLastError(E_INVALIDARG);
605 ret = FALSE;
606 break;
607 case CERT_ACCESS_STATE_PROP_ID:
608 if (!pvData)
610 *pcbData = sizeof(DWORD);
611 ret = TRUE;
613 else if (*pcbData < sizeof(DWORD))
615 SetLastError(ERROR_MORE_DATA);
616 *pcbData = sizeof(DWORD);
617 ret = FALSE;
619 else
621 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId, pvData, pcbData);
623 break;
624 default:
625 ret = CTLContext_GetProperty(ctl_from_ptr(pCTLContext), dwPropId, pvData,
626 pcbData);
628 return ret;
631 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
632 DWORD dwFlags, const void *pvData)
634 BOOL ret;
636 TRACE("(%p, %d, %08x, %p)\n", ctl, dwPropId, dwFlags, pvData);
638 if (!ctl->base.properties)
639 ret = FALSE;
640 else if (!pvData)
642 ContextPropertyList_RemoveProperty(ctl->base.properties, dwPropId);
643 ret = TRUE;
645 else
647 switch (dwPropId)
649 case CERT_AUTO_ENROLL_PROP_ID:
650 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
651 case CERT_DESCRIPTION_PROP_ID:
652 case CERT_FRIENDLY_NAME_PROP_ID:
653 case CERT_HASH_PROP_ID:
654 case CERT_KEY_IDENTIFIER_PROP_ID:
655 case CERT_MD5_HASH_PROP_ID:
656 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
657 case CERT_PUBKEY_ALG_PARA_PROP_ID:
658 case CERT_PVK_FILE_PROP_ID:
659 case CERT_SIGNATURE_HASH_PROP_ID:
660 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
661 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
662 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
663 case CERT_ENROLLMENT_PROP_ID:
664 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
665 case CERT_RENEWAL_PROP_ID:
667 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
669 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
670 blob->pbData, blob->cbData);
671 break;
673 case CERT_DATE_STAMP_PROP_ID:
674 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
675 pvData, sizeof(FILETIME));
676 break;
677 default:
678 FIXME("%d: stub\n", dwPropId);
679 ret = FALSE;
682 TRACE("returning %d\n", ret);
683 return ret;
686 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
687 DWORD dwPropId, DWORD dwFlags, const void *pvData)
689 BOOL ret;
691 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
693 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
694 * crashes on most of these, I'll be safer.
696 switch (dwPropId)
698 case 0:
699 case CERT_ACCESS_STATE_PROP_ID:
700 case CERT_CERT_PROP_ID:
701 case CERT_CRL_PROP_ID:
702 case CERT_CTL_PROP_ID:
703 SetLastError(E_INVALIDARG);
704 return FALSE;
706 ret = CTLContext_SetProperty(ctl_from_ptr(pCTLContext), dwPropId, dwFlags, pvData);
707 TRACE("returning %d\n", ret);
708 return ret;