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
23 #define NONAMELESSUNION
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
)
46 ctl
= (ctl_t
*)Context_CreateLinkContext(sizeof(CTL_CONTEXT
), context
);
50 ctl
->ctx
.hCertStore
= store
;
54 static const context_vtbl_t ctl_vtbl
= {
59 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
60 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
61 PCCTL_CONTEXT
* ppStoreContext
)
63 WINECRYPT_CERTSTORE
*store
= hCertStore
;
65 PCCTL_CONTEXT toAdd
= NULL
, existing
= NULL
;
67 TRACE("(%p, %p, %08x, %p)\n", hCertStore
, pCtlContext
, dwAddDisposition
,
70 if (dwAddDisposition
!= CERT_STORE_ADD_ALWAYS
)
72 existing
= CertFindCTLInStore(hCertStore
, 0, 0, CTL_FIND_EXISTING
,
76 switch (dwAddDisposition
)
78 case CERT_STORE_ADD_ALWAYS
:
79 toAdd
= CertDuplicateCTLContext(pCtlContext
);
81 case CERT_STORE_ADD_NEW
:
84 TRACE("found matching CTL, not adding\n");
85 SetLastError(CRYPT_E_EXISTS
);
89 toAdd
= CertDuplicateCTLContext(pCtlContext
);
91 case CERT_STORE_ADD_NEWER
:
94 LONG newer
= CompareFileTime(&existing
->pCtlInfo
->ThisUpdate
,
95 &pCtlContext
->pCtlInfo
->ThisUpdate
);
98 toAdd
= CertDuplicateCTLContext(pCtlContext
);
101 TRACE("existing CTL is newer, not adding\n");
102 SetLastError(CRYPT_E_EXISTS
);
107 toAdd
= CertDuplicateCTLContext(pCtlContext
);
109 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
:
112 LONG newer
= CompareFileTime(&existing
->pCtlInfo
->ThisUpdate
,
113 &pCtlContext
->pCtlInfo
->ThisUpdate
);
117 toAdd
= CertDuplicateCTLContext(pCtlContext
);
118 Context_CopyProperties(existing
, pCtlContext
);
122 TRACE("existing CTL is newer, not adding\n");
123 SetLastError(CRYPT_E_EXISTS
);
128 toAdd
= CertDuplicateCTLContext(pCtlContext
);
130 case CERT_STORE_ADD_REPLACE_EXISTING
:
131 toAdd
= CertDuplicateCTLContext(pCtlContext
);
133 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
:
134 toAdd
= CertDuplicateCTLContext(pCtlContext
);
136 Context_CopyProperties(toAdd
, existing
);
138 case CERT_STORE_ADD_USE_EXISTING
:
141 Context_CopyProperties(existing
, pCtlContext
);
143 *ppStoreContext
= CertDuplicateCTLContext(existing
);
146 toAdd
= CertDuplicateCTLContext(pCtlContext
);
149 FIXME("Unimplemented add disposition %d\n", dwAddDisposition
);
156 ret
= store
->vtbl
->ctls
.addContext(store
, (void *)toAdd
,
157 (void *)existing
, (const void **)ppStoreContext
);
158 else if (ppStoreContext
)
159 *ppStoreContext
= CertDuplicateCTLContext(toAdd
);
160 CertFreeCTLContext(toAdd
);
162 CertFreeCTLContext(existing
);
164 TRACE("returning %d\n", ret
);
168 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
169 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
170 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
172 PCCTL_CONTEXT ctl
= CertCreateCTLContext(dwMsgAndCertEncodingType
,
173 pbCtlEncoded
, cbCtlEncoded
);
176 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore
,
177 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
182 ret
= CertAddCTLContextToStore(hCertStore
, ctl
, dwAddDisposition
,
184 CertFreeCTLContext(ctl
);
191 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
194 WINECRYPT_CERTSTORE
*hcs
= hCertStore
;
197 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
200 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
203 ret
= (PCCTL_CONTEXT
)hcs
->vtbl
->ctls
.enumContext(hcs
, (void *)pPrev
);
207 typedef BOOL (*CtlCompareFunc
)(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
208 DWORD dwFlags
, const void *pvPara
);
210 static BOOL
compare_ctl_any(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
211 DWORD dwFlags
, const void *pvPara
)
216 static BOOL
compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
217 DWORD dwFlags
, const void *pvPara
)
221 DWORD size
= sizeof(hash
);
223 ret
= CertGetCTLContextProperty(pCtlContext
, CERT_MD5_HASH_PROP_ID
, hash
,
227 const CRYPT_HASH_BLOB
*pHash
= pvPara
;
229 if (size
== pHash
->cbData
)
230 ret
= !memcmp(pHash
->pbData
, hash
, size
);
237 static BOOL
compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
238 DWORD dwFlags
, const void *pvPara
)
242 DWORD size
= sizeof(hash
);
244 ret
= CertGetCTLContextProperty(pCtlContext
, CERT_SHA1_HASH_PROP_ID
, hash
,
248 const CRYPT_HASH_BLOB
*pHash
= pvPara
;
250 if (size
== pHash
->cbData
)
251 ret
= !memcmp(pHash
->pbData
, hash
, size
);
258 static BOOL
compare_ctl_existing(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
259 DWORD dwFlags
, const void *pvPara
)
265 PCCTL_CONTEXT ctl
= pvPara
;
267 if (pCtlContext
->cbCtlContext
== ctl
->cbCtlContext
)
269 if (ctl
->cbCtlContext
)
270 ret
= !memcmp(pCtlContext
->pbCtlContext
, ctl
->pbCtlContext
,
283 PCCTL_CONTEXT WINAPI
CertFindCTLInStore(HCERTSTORE hCertStore
,
284 DWORD dwCertEncodingType
, DWORD dwFindFlags
, DWORD dwFindType
,
285 const void *pvFindPara
, PCCTL_CONTEXT pPrevCtlContext
)
288 CtlCompareFunc compare
;
290 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore
, dwCertEncodingType
,
291 dwFindFlags
, dwFindType
, pvFindPara
, pPrevCtlContext
);
296 compare
= compare_ctl_any
;
298 case CTL_FIND_SHA1_HASH
:
299 compare
= compare_ctl_by_sha1_hash
;
301 case CTL_FIND_MD5_HASH
:
302 compare
= compare_ctl_by_md5_hash
;
304 case CTL_FIND_EXISTING
:
305 compare
= compare_ctl_existing
;
308 FIXME("find type %08x unimplemented\n", dwFindType
);
314 BOOL matches
= FALSE
;
316 ret
= pPrevCtlContext
;
318 ret
= CertEnumCTLsInStore(hCertStore
, ret
);
320 matches
= compare(ret
, dwFindType
, dwFindFlags
, pvFindPara
);
321 } while (ret
!= NULL
&& !matches
);
323 SetLastError(CRYPT_E_NOT_FOUND
);
327 SetLastError(CRYPT_E_NOT_FOUND
);
333 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
337 TRACE("(%p)\n", pCtlContext
);
341 else if (!pCtlContext
->hCertStore
)
342 ret
= CertFreeCTLContext(pCtlContext
);
345 WINECRYPT_CERTSTORE
*hcs
= pCtlContext
->hCertStore
;
346 ctl_t
*ctl
= ctl_from_ptr(pCtlContext
);
348 if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
351 ret
= hcs
->vtbl
->ctls
.delete(hcs
, &ctl
->base
);
353 ret
= CertFreeCTLContext(pCtlContext
);
358 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwMsgAndCertEncodingType
,
359 const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
)
361 PCTL_CONTEXT ctl
= NULL
;
364 BYTE
*content
= NULL
;
365 DWORD contentSize
= 0, size
;
366 PCTL_INFO ctlInfo
= NULL
;
368 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType
, pbCtlEncoded
,
371 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType
) != X509_ASN_ENCODING
)
373 SetLastError(E_INVALIDARG
);
376 if (!pbCtlEncoded
|| !cbCtlEncoded
)
378 SetLastError(ERROR_INVALID_DATA
);
381 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
| X509_ASN_ENCODING
, 0, 0,
385 ret
= CryptMsgUpdate(msg
, pbCtlEncoded
, cbCtlEncoded
, TRUE
);
388 SetLastError(ERROR_INVALID_DATA
);
391 /* Check that it's really a CTL */
392 ret
= CryptMsgGetParam(msg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0, NULL
, &size
);
395 char *innerContent
= CryptMemAlloc(size
);
399 ret
= CryptMsgGetParam(msg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0,
400 innerContent
, &size
);
403 if (strcmp(innerContent
, szOID_CTL
))
405 SetLastError(ERROR_INVALID_DATA
);
409 CryptMemFree(innerContent
);
413 SetLastError(ERROR_OUTOFMEMORY
);
419 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, NULL
, &contentSize
);
422 content
= CryptMemAlloc(contentSize
);
425 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, content
,
429 ret
= CryptDecodeObjectEx(dwMsgAndCertEncodingType
, PKCS_CTL
,
430 content
, contentSize
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
434 ctl
= Context_CreateDataContext(sizeof(CTL_CONTEXT
), &ctl_vtbl
);
437 BYTE
*data
= CryptMemAlloc(cbCtlEncoded
);
441 memcpy(data
, pbCtlEncoded
, cbCtlEncoded
);
442 ctl
->dwMsgAndCertEncodingType
=
443 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
;
444 ctl
->pbCtlEncoded
= data
;
445 ctl
->cbCtlEncoded
= cbCtlEncoded
;
446 ctl
->pCtlInfo
= ctlInfo
;
447 ctl
->hCertStore
= NULL
;
448 ctl
->hCryptMsg
= msg
;
449 ctl
->pbCtlContext
= content
;
450 ctl
->cbCtlContext
= contentSize
;
454 SetLastError(ERROR_OUTOFMEMORY
);
460 SetLastError(ERROR_OUTOFMEMORY
);
468 SetLastError(ERROR_OUTOFMEMORY
);
475 CertFreeCTLContext(ctl
);
478 CryptMemFree(content
);
484 PCCTL_CONTEXT WINAPI
CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext
)
486 TRACE("(%p)\n", pCtlContext
);
488 Context_AddRef(&ctl_from_ptr(pCtlContext
)->base
);
492 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCTLContext
)
496 TRACE("(%p)\n", pCTLContext
);
499 ret
= Context_Release(&ctl_from_ptr(pCTLContext
)->base
);
503 DWORD WINAPI
CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext
,
506 CONTEXT_PROPERTY_LIST
*properties
= Context_GetProperties(pCTLContext
);
509 TRACE("(%p, %d)\n", pCTLContext
, dwPropId
);
512 ret
= ContextPropertyList_EnumPropIDs(properties
, dwPropId
);
518 static BOOL
CTLContext_SetProperty(PCCTL_CONTEXT context
, DWORD dwPropId
,
519 DWORD dwFlags
, const void *pvData
);
521 static BOOL
CTLContext_GetHashProp(PCCTL_CONTEXT context
, DWORD dwPropId
,
522 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
525 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
529 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
531 ret
= CTLContext_SetProperty(context
, dwPropId
, 0, &blob
);
536 static BOOL
CTLContext_GetProperty(PCCTL_CONTEXT context
, DWORD dwPropId
,
537 void *pvData
, DWORD
*pcbData
)
539 CONTEXT_PROPERTY_LIST
*properties
= Context_GetProperties(context
);
541 CRYPT_DATA_BLOB blob
;
543 TRACE("(%p, %d, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
546 ret
= ContextPropertyList_FindProperty(properties
, dwPropId
, &blob
);
552 *pcbData
= blob
.cbData
;
553 else if (*pcbData
< blob
.cbData
)
555 SetLastError(ERROR_MORE_DATA
);
556 *pcbData
= blob
.cbData
;
561 memcpy(pvData
, blob
.pbData
, blob
.cbData
);
562 *pcbData
= blob
.cbData
;
567 /* Implicit properties */
570 case CERT_SHA1_HASH_PROP_ID
:
571 ret
= CTLContext_GetHashProp(context
, dwPropId
, CALG_SHA1
,
572 context
->pbCtlEncoded
, context
->cbCtlEncoded
, pvData
, pcbData
);
574 case CERT_MD5_HASH_PROP_ID
:
575 ret
= CTLContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
576 context
->pbCtlEncoded
, context
->cbCtlEncoded
, pvData
, pcbData
);
579 SetLastError(CRYPT_E_NOT_FOUND
);
582 TRACE("returning %d\n", ret
);
586 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
587 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
591 TRACE("(%p, %d, %p, %p)\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
596 case CERT_CERT_PROP_ID
:
597 case CERT_CRL_PROP_ID
:
598 case CERT_CTL_PROP_ID
:
599 SetLastError(E_INVALIDARG
);
602 case CERT_ACCESS_STATE_PROP_ID
:
605 *pcbData
= sizeof(DWORD
);
608 else if (*pcbData
< sizeof(DWORD
))
610 SetLastError(ERROR_MORE_DATA
);
611 *pcbData
= sizeof(DWORD
);
616 if (pCTLContext
->hCertStore
)
617 ret
= CertGetStoreProperty(pCTLContext
->hCertStore
, dwPropId
,
621 *(DWORD
*)pvData
= 0;
627 ret
= CTLContext_GetProperty(pCTLContext
, dwPropId
, pvData
,
633 static BOOL
CTLContext_SetProperty(PCCTL_CONTEXT context
, DWORD dwPropId
,
634 DWORD dwFlags
, const void *pvData
)
636 CONTEXT_PROPERTY_LIST
*properties
= Context_GetProperties(context
);
639 TRACE("(%p, %d, %08x, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
645 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
652 case CERT_AUTO_ENROLL_PROP_ID
:
653 case CERT_CTL_USAGE_PROP_ID
: /* same as CERT_ENHKEY_USAGE_PROP_ID */
654 case CERT_DESCRIPTION_PROP_ID
:
655 case CERT_FRIENDLY_NAME_PROP_ID
:
656 case CERT_HASH_PROP_ID
:
657 case CERT_KEY_IDENTIFIER_PROP_ID
:
658 case CERT_MD5_HASH_PROP_ID
:
659 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
660 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
661 case CERT_PVK_FILE_PROP_ID
:
662 case CERT_SIGNATURE_HASH_PROP_ID
:
663 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
664 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
665 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
666 case CERT_ENROLLMENT_PROP_ID
:
667 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
668 case CERT_RENEWAL_PROP_ID
:
670 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
672 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
673 blob
->pbData
, blob
->cbData
);
676 case CERT_DATE_STAMP_PROP_ID
:
677 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
678 pvData
, sizeof(FILETIME
));
681 FIXME("%d: stub\n", dwPropId
);
685 TRACE("returning %d\n", ret
);
689 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
690 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
694 TRACE("(%p, %d, %08x, %p)\n", pCTLContext
, dwPropId
, dwFlags
, pvData
);
696 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
697 * crashes on most of these, I'll be safer.
702 case CERT_ACCESS_STATE_PROP_ID
:
703 case CERT_CERT_PROP_ID
:
704 case CERT_CRL_PROP_ID
:
705 case CERT_CTL_PROP_ID
:
706 SetLastError(E_INVALIDARG
);
709 ret
= CTLContext_SetProperty(pCTLContext
, dwPropId
, dwFlags
, pvData
);
710 TRACE("returning %d\n", ret
);