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
26 #include "wine/debug.h"
27 #include "crypt32_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
31 static void CTL_free(context_t
*context
)
33 ctl_t
*ctl
= (ctl_t
*)context
;
35 CryptMsgClose(ctl
->ctx
.hCryptMsg
);
36 CryptMemFree(ctl
->ctx
.pbCtlEncoded
);
37 CryptMemFree(ctl
->ctx
.pbCtlContext
);
38 LocalFree(ctl
->ctx
.pCtlInfo
);
41 static context_t
*CTL_clone(context_t
*context
, WINECRYPT_CERTSTORE
*store
, BOOL use_link
)
46 FIXME("Only links supported\n");
50 ctl
= (ctl_t
*)Context_CreateLinkContext(sizeof(CTL_CONTEXT
), context
, store
);
54 ctl
->ctx
.hCertStore
= store
;
58 static const context_vtbl_t ctl_vtbl
= {
63 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
64 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
65 PCCTL_CONTEXT
* ppStoreContext
)
67 WINECRYPT_CERTSTORE
*store
= hCertStore
;
69 PCCTL_CONTEXT toAdd
= NULL
, existing
= NULL
;
71 TRACE("(%p, %p, %08x, %p)\n", hCertStore
, pCtlContext
, dwAddDisposition
,
74 if (dwAddDisposition
!= CERT_STORE_ADD_ALWAYS
)
76 existing
= CertFindCTLInStore(hCertStore
, 0, 0, CTL_FIND_EXISTING
,
80 switch (dwAddDisposition
)
82 case CERT_STORE_ADD_ALWAYS
:
83 toAdd
= CertDuplicateCTLContext(pCtlContext
);
85 case CERT_STORE_ADD_NEW
:
88 TRACE("found matching CTL, not adding\n");
89 SetLastError(CRYPT_E_EXISTS
);
93 toAdd
= CertDuplicateCTLContext(pCtlContext
);
95 case CERT_STORE_ADD_NEWER
:
98 LONG newer
= CompareFileTime(&existing
->pCtlInfo
->ThisUpdate
,
99 &pCtlContext
->pCtlInfo
->ThisUpdate
);
102 toAdd
= CertDuplicateCTLContext(pCtlContext
);
105 TRACE("existing CTL is newer, not adding\n");
106 SetLastError(CRYPT_E_EXISTS
);
111 toAdd
= CertDuplicateCTLContext(pCtlContext
);
113 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
:
116 LONG newer
= CompareFileTime(&existing
->pCtlInfo
->ThisUpdate
,
117 &pCtlContext
->pCtlInfo
->ThisUpdate
);
121 toAdd
= CertDuplicateCTLContext(pCtlContext
);
122 Context_CopyProperties(existing
, pCtlContext
);
126 TRACE("existing CTL is newer, not adding\n");
127 SetLastError(CRYPT_E_EXISTS
);
132 toAdd
= CertDuplicateCTLContext(pCtlContext
);
134 case CERT_STORE_ADD_REPLACE_EXISTING
:
135 toAdd
= CertDuplicateCTLContext(pCtlContext
);
137 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
:
138 toAdd
= CertDuplicateCTLContext(pCtlContext
);
140 Context_CopyProperties(toAdd
, existing
);
142 case CERT_STORE_ADD_USE_EXISTING
:
145 Context_CopyProperties(existing
, pCtlContext
);
147 *ppStoreContext
= CertDuplicateCTLContext(existing
);
150 toAdd
= CertDuplicateCTLContext(pCtlContext
);
153 FIXME("Unimplemented add disposition %d\n", dwAddDisposition
);
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
);
169 CertFreeCTLContext(toAdd
);
171 CertFreeCTLContext(existing
);
173 TRACE("returning %d\n", ret
);
177 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
178 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
179 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
181 PCCTL_CONTEXT ctl
= CertCreateCTLContext(dwMsgAndCertEncodingType
,
182 pbCtlEncoded
, cbCtlEncoded
);
185 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore
,
186 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
191 ret
= CertAddCTLContextToStore(hCertStore
, ctl
, dwAddDisposition
,
193 CertFreeCTLContext(ctl
);
200 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
, PCCTL_CONTEXT pPrev
)
202 ctl_t
*prev
= pPrev
? ctl_from_ptr(pPrev
) : NULL
, *ret
;
203 WINECRYPT_CERTSTORE
*hcs
= hCertStore
;
205 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
208 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
211 ret
= (ctl_t
*)hcs
->vtbl
->ctls
.enumContext(hcs
, prev
? &prev
->base
: NULL
);
212 return ret
? &ret
->ctx
: NULL
;
215 typedef BOOL (*CtlCompareFunc
)(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
216 DWORD dwFlags
, const void *pvPara
);
218 static BOOL
compare_ctl_any(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
219 DWORD dwFlags
, const void *pvPara
)
224 static BOOL
compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
225 DWORD dwFlags
, const void *pvPara
)
229 DWORD size
= sizeof(hash
);
231 ret
= CertGetCTLContextProperty(pCtlContext
, CERT_MD5_HASH_PROP_ID
, hash
,
235 const CRYPT_HASH_BLOB
*pHash
= pvPara
;
237 if (size
== pHash
->cbData
)
238 ret
= !memcmp(pHash
->pbData
, hash
, size
);
245 static BOOL
compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
246 DWORD dwFlags
, const void *pvPara
)
250 DWORD size
= sizeof(hash
);
252 ret
= CertGetCTLContextProperty(pCtlContext
, CERT_SHA1_HASH_PROP_ID
, hash
,
256 const CRYPT_HASH_BLOB
*pHash
= pvPara
;
258 if (size
== pHash
->cbData
)
259 ret
= !memcmp(pHash
->pbData
, hash
, size
);
266 static BOOL
compare_ctl_existing(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
267 DWORD dwFlags
, const void *pvPara
)
273 PCCTL_CONTEXT ctl
= pvPara
;
275 if (pCtlContext
->cbCtlContext
== ctl
->cbCtlContext
)
277 if (ctl
->cbCtlContext
)
278 ret
= !memcmp(pCtlContext
->pbCtlContext
, ctl
->pbCtlContext
,
291 PCCTL_CONTEXT WINAPI
CertFindCTLInStore(HCERTSTORE hCertStore
,
292 DWORD dwCertEncodingType
, DWORD dwFindFlags
, DWORD dwFindType
,
293 const void *pvFindPara
, PCCTL_CONTEXT pPrevCtlContext
)
296 CtlCompareFunc compare
;
298 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore
, dwCertEncodingType
,
299 dwFindFlags
, dwFindType
, pvFindPara
, pPrevCtlContext
);
304 compare
= compare_ctl_any
;
306 case CTL_FIND_SHA1_HASH
:
307 compare
= compare_ctl_by_sha1_hash
;
309 case CTL_FIND_MD5_HASH
:
310 compare
= compare_ctl_by_md5_hash
;
312 case CTL_FIND_EXISTING
:
313 compare
= compare_ctl_existing
;
316 FIXME("find type %08x unimplemented\n", dwFindType
);
322 BOOL matches
= FALSE
;
324 ret
= pPrevCtlContext
;
326 ret
= CertEnumCTLsInStore(hCertStore
, ret
);
328 matches
= compare(ret
, dwFindType
, dwFindFlags
, pvFindPara
);
329 } while (ret
!= NULL
&& !matches
);
331 SetLastError(CRYPT_E_NOT_FOUND
);
335 SetLastError(CRYPT_E_NOT_FOUND
);
341 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
343 WINECRYPT_CERTSTORE
*hcs
;
344 ctl_t
*ctl
= ctl_from_ptr(pCtlContext
);
347 TRACE("(%p)\n", pCtlContext
);
352 hcs
= pCtlContext
->hCertStore
;
354 if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
357 ret
= hcs
->vtbl
->ctls
.delete(hcs
, &ctl
->base
);
359 ret
= CertFreeCTLContext(pCtlContext
);
363 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwMsgAndCertEncodingType
,
364 const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
)
369 BYTE
*content
= NULL
;
370 DWORD contentSize
= 0, size
;
371 PCTL_INFO ctlInfo
= NULL
;
373 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType
, pbCtlEncoded
,
376 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType
) != X509_ASN_ENCODING
)
378 SetLastError(E_INVALIDARG
);
381 if (!pbCtlEncoded
|| !cbCtlEncoded
)
383 SetLastError(ERROR_INVALID_DATA
);
386 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
| X509_ASN_ENCODING
, 0, 0,
390 ret
= CryptMsgUpdate(msg
, pbCtlEncoded
, cbCtlEncoded
, TRUE
);
393 SetLastError(ERROR_INVALID_DATA
);
396 /* Check that it's really a CTL */
397 ret
= CryptMsgGetParam(msg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0, NULL
, &size
);
400 char *innerContent
= CryptMemAlloc(size
);
404 ret
= CryptMsgGetParam(msg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0,
405 innerContent
, &size
);
408 if (strcmp(innerContent
, szOID_CTL
))
410 SetLastError(ERROR_INVALID_DATA
);
414 CryptMemFree(innerContent
);
418 SetLastError(ERROR_OUTOFMEMORY
);
424 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, NULL
, &contentSize
);
427 content
= CryptMemAlloc(contentSize
);
430 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, content
,
434 ret
= CryptDecodeObjectEx(dwMsgAndCertEncodingType
, PKCS_CTL
,
435 content
, contentSize
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
439 ctl
= (ctl_t
*)Context_CreateDataContext(sizeof(CTL_CONTEXT
), &ctl_vtbl
, &empty_store
);
442 BYTE
*data
= CryptMemAlloc(cbCtlEncoded
);
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
;
459 SetLastError(ERROR_OUTOFMEMORY
);
465 SetLastError(ERROR_OUTOFMEMORY
);
473 SetLastError(ERROR_OUTOFMEMORY
);
481 Context_Release(&ctl
->base
);
484 CryptMemFree(content
);
491 PCCTL_CONTEXT WINAPI
CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext
)
493 TRACE("(%p)\n", pCtlContext
);
495 Context_AddRef(&ctl_from_ptr(pCtlContext
)->base
);
499 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCTLContext
)
501 TRACE("(%p)\n", pCTLContext
);
504 Context_Release(&ctl_from_ptr(pCTLContext
)->base
);
508 DWORD WINAPI
CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext
,
511 ctl_t
*ctl
= ctl_from_ptr(pCTLContext
);
514 TRACE("(%p, %d)\n", pCTLContext
, dwPropId
);
516 if (ctl
->base
.properties
)
517 ret
= ContextPropertyList_EnumPropIDs(ctl
->base
.properties
, dwPropId
);
523 static BOOL
CTLContext_SetProperty(ctl_t
*ctl
, DWORD dwPropId
,
524 DWORD dwFlags
, const void *pvData
);
526 static BOOL
CTLContext_GetHashProp(ctl_t
*ctl
, DWORD dwPropId
,
527 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
530 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
534 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
536 ret
= CTLContext_SetProperty(ctl
, dwPropId
, 0, &blob
);
541 static BOOL
CTLContext_GetProperty(ctl_t
*ctl
, DWORD dwPropId
,
542 void *pvData
, DWORD
*pcbData
)
545 CRYPT_DATA_BLOB blob
;
547 TRACE("(%p, %d, %p, %p)\n", ctl
, dwPropId
, pvData
, pcbData
);
549 if (ctl
->base
.properties
)
550 ret
= ContextPropertyList_FindProperty(ctl
->base
.properties
, dwPropId
, &blob
);
556 *pcbData
= blob
.cbData
;
557 else if (*pcbData
< blob
.cbData
)
559 SetLastError(ERROR_MORE_DATA
);
560 *pcbData
= blob
.cbData
;
565 memcpy(pvData
, blob
.pbData
, blob
.cbData
);
566 *pcbData
= blob
.cbData
;
571 /* Implicit properties */
574 case CERT_SHA1_HASH_PROP_ID
:
575 ret
= CTLContext_GetHashProp(ctl
, dwPropId
, CALG_SHA1
,
576 ctl
->ctx
.pbCtlEncoded
, ctl
->ctx
.cbCtlEncoded
, pvData
, pcbData
);
578 case CERT_MD5_HASH_PROP_ID
:
579 ret
= CTLContext_GetHashProp(ctl
, dwPropId
, CALG_MD5
,
580 ctl
->ctx
.pbCtlEncoded
, ctl
->ctx
.cbCtlEncoded
, pvData
, pcbData
);
583 SetLastError(CRYPT_E_NOT_FOUND
);
586 TRACE("returning %d\n", ret
);
590 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
591 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
595 TRACE("(%p, %d, %p, %p)\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
600 case CERT_CERT_PROP_ID
:
601 case CERT_CRL_PROP_ID
:
602 case CERT_CTL_PROP_ID
:
603 SetLastError(E_INVALIDARG
);
606 case CERT_ACCESS_STATE_PROP_ID
:
609 *pcbData
= sizeof(DWORD
);
612 else if (*pcbData
< sizeof(DWORD
))
614 SetLastError(ERROR_MORE_DATA
);
615 *pcbData
= sizeof(DWORD
);
620 ret
= CertGetStoreProperty(pCTLContext
->hCertStore
, dwPropId
, pvData
, pcbData
);
624 ret
= CTLContext_GetProperty(ctl_from_ptr(pCTLContext
), dwPropId
, pvData
,
630 static BOOL
CTLContext_SetProperty(ctl_t
*ctl
, DWORD dwPropId
,
631 DWORD dwFlags
, const void *pvData
)
635 TRACE("(%p, %d, %08x, %p)\n", ctl
, dwPropId
, dwFlags
, pvData
);
637 if (!ctl
->base
.properties
)
641 ContextPropertyList_RemoveProperty(ctl
->base
.properties
, dwPropId
);
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
:
666 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
668 ret
= ContextPropertyList_SetProperty(ctl
->base
.properties
, dwPropId
,
669 blob
->pbData
, blob
->cbData
);
672 case CERT_DATE_STAMP_PROP_ID
:
673 ret
= ContextPropertyList_SetProperty(ctl
->base
.properties
, dwPropId
,
674 pvData
, sizeof(FILETIME
));
677 FIXME("%d: stub\n", dwPropId
);
681 TRACE("returning %d\n", ret
);
685 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
686 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
690 TRACE("(%p, %d, %08x, %p)\n", pCTLContext
, dwPropId
, dwFlags
, pvData
);
692 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
693 * crashes on most of these, I'll be safer.
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
);
705 ret
= CTLContext_SetProperty(ctl_from_ptr(pCTLContext
), dwPropId
, dwFlags
, pvData
);
706 TRACE("returning %d\n", ret
);