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 #define CtlContext_CopyProperties(to, from) \
33 Context_CopyProperties((to), (from), sizeof(CTL_CONTEXT))
35 BOOL WINAPI
CertAddCTLContextToStore(HCERTSTORE hCertStore
,
36 PCCTL_CONTEXT pCtlContext
, DWORD dwAddDisposition
,
37 PCCTL_CONTEXT
* ppStoreContext
)
39 PWINECRYPT_CERTSTORE store
= (PWINECRYPT_CERTSTORE
)hCertStore
;
41 PCCTL_CONTEXT toAdd
= NULL
, existing
= NULL
;
43 TRACE("(%p, %p, %08x, %p)\n", hCertStore
, pCtlContext
, dwAddDisposition
,
46 if (dwAddDisposition
!= CERT_STORE_ADD_ALWAYS
)
48 existing
= CertFindCTLInStore(hCertStore
, 0, 0, CTL_FIND_EXISTING
,
52 switch (dwAddDisposition
)
54 case CERT_STORE_ADD_ALWAYS
:
55 toAdd
= CertDuplicateCTLContext(pCtlContext
);
57 case CERT_STORE_ADD_NEW
:
60 TRACE("found matching CTL, not adding\n");
61 SetLastError(CRYPT_E_EXISTS
);
65 toAdd
= CertDuplicateCTLContext(pCtlContext
);
67 case CERT_STORE_ADD_NEWER
:
70 LONG newer
= CompareFileTime(&existing
->pCtlInfo
->ThisUpdate
,
71 &pCtlContext
->pCtlInfo
->ThisUpdate
);
74 toAdd
= CertDuplicateCTLContext(pCtlContext
);
77 TRACE("existing CTL is newer, not adding\n");
78 SetLastError(CRYPT_E_EXISTS
);
83 toAdd
= CertDuplicateCTLContext(pCtlContext
);
85 case CERT_STORE_ADD_REPLACE_EXISTING
:
86 toAdd
= CertDuplicateCTLContext(pCtlContext
);
88 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
:
89 toAdd
= CertDuplicateCTLContext(pCtlContext
);
91 CtlContext_CopyProperties(toAdd
, existing
);
93 case CERT_STORE_ADD_USE_EXISTING
:
95 CtlContext_CopyProperties(existing
, pCtlContext
);
98 FIXME("Unimplemented add disposition %d\n", dwAddDisposition
);
105 ret
= store
->ctls
.addContext(store
, (void *)toAdd
,
106 (void *)existing
, (const void **)ppStoreContext
);
107 else if (ppStoreContext
)
108 *ppStoreContext
= CertDuplicateCTLContext(toAdd
);
109 CertFreeCTLContext(toAdd
);
111 CertFreeCTLContext(existing
);
113 TRACE("returning %d\n", ret
);
117 BOOL WINAPI
CertAddEncodedCTLToStore(HCERTSTORE hCertStore
,
118 DWORD dwMsgAndCertEncodingType
, const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
,
119 DWORD dwAddDisposition
, PCCTL_CONTEXT
*ppCtlContext
)
121 PCCTL_CONTEXT ctl
= CertCreateCTLContext(dwMsgAndCertEncodingType
,
122 pbCtlEncoded
, cbCtlEncoded
);
125 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore
,
126 dwMsgAndCertEncodingType
, pbCtlEncoded
, cbCtlEncoded
, dwAddDisposition
,
131 ret
= CertAddCTLContextToStore(hCertStore
, ctl
, dwAddDisposition
,
133 CertFreeCTLContext(ctl
);
140 PCCTL_CONTEXT WINAPI
CertEnumCTLsInStore(HCERTSTORE hCertStore
,
143 WINECRYPT_CERTSTORE
*hcs
= (WINECRYPT_CERTSTORE
*)hCertStore
;
146 TRACE("(%p, %p)\n", hCertStore
, pPrev
);
149 else if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
152 ret
= (PCCTL_CONTEXT
)hcs
->ctls
.enumContext(hcs
, (void *)pPrev
);
156 typedef BOOL (*CtlCompareFunc
)(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
157 DWORD dwFlags
, const void *pvPara
);
159 static BOOL
compare_ctl_any(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
160 DWORD dwFlags
, const void *pvPara
)
165 static BOOL
compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
166 DWORD dwFlags
, const void *pvPara
)
170 DWORD size
= sizeof(hash
);
172 ret
= CertGetCTLContextProperty(pCtlContext
, CERT_MD5_HASH_PROP_ID
, hash
,
176 const CRYPT_HASH_BLOB
*pHash
= (const CRYPT_HASH_BLOB
*)pvPara
;
178 if (size
== pHash
->cbData
)
179 ret
= !memcmp(pHash
->pbData
, hash
, size
);
186 static BOOL
compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
187 DWORD dwFlags
, const void *pvPara
)
191 DWORD size
= sizeof(hash
);
193 ret
= CertGetCTLContextProperty(pCtlContext
, CERT_SHA1_HASH_PROP_ID
, hash
,
197 const CRYPT_HASH_BLOB
*pHash
= (const CRYPT_HASH_BLOB
*)pvPara
;
199 if (size
== pHash
->cbData
)
200 ret
= !memcmp(pHash
->pbData
, hash
, size
);
207 static BOOL
compare_ctl_existing(PCCTL_CONTEXT pCtlContext
, DWORD dwType
,
208 DWORD dwFlags
, const void *pvPara
)
214 PCCTL_CONTEXT ctl
= (PCCTL_CONTEXT
)pvPara
;
216 if (pCtlContext
->cbCtlContext
== ctl
->cbCtlContext
)
218 if (ctl
->cbCtlContext
)
219 ret
= !memcmp(pCtlContext
->pbCtlContext
, ctl
->pbCtlContext
,
232 PCCTL_CONTEXT WINAPI
CertFindCTLInStore(HCERTSTORE hCertStore
,
233 DWORD dwCertEncodingType
, DWORD dwFindFlags
, DWORD dwFindType
,
234 const void *pvFindPara
, PCCTL_CONTEXT pPrevCtlContext
)
237 CtlCompareFunc compare
;
239 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore
, dwCertEncodingType
,
240 dwFindFlags
, dwFindType
, pvFindPara
, pPrevCtlContext
);
245 compare
= compare_ctl_any
;
247 case CTL_FIND_SHA1_HASH
:
248 compare
= compare_ctl_by_sha1_hash
;
250 case CTL_FIND_MD5_HASH
:
251 compare
= compare_ctl_by_md5_hash
;
253 case CTL_FIND_EXISTING
:
254 compare
= compare_ctl_existing
;
257 FIXME("find type %08x unimplemented\n", dwFindType
);
263 BOOL matches
= FALSE
;
265 ret
= pPrevCtlContext
;
267 ret
= CertEnumCTLsInStore(hCertStore
, ret
);
269 matches
= compare(ret
, dwFindType
, dwFindFlags
, pvFindPara
);
270 } while (ret
!= NULL
&& !matches
);
272 SetLastError(CRYPT_E_NOT_FOUND
);
276 SetLastError(CRYPT_E_NOT_FOUND
);
282 BOOL WINAPI
CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext
)
286 TRACE("(%p)\n", pCtlContext
);
290 else if (!pCtlContext
->hCertStore
)
293 CertFreeCTLContext(pCtlContext
);
297 PWINECRYPT_CERTSTORE hcs
=
298 (PWINECRYPT_CERTSTORE
)pCtlContext
->hCertStore
;
300 if (hcs
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
303 ret
= hcs
->ctls
.deleteContext(hcs
, (void *)pCtlContext
);
304 CertFreeCTLContext(pCtlContext
);
309 PCCTL_CONTEXT WINAPI
CertCreateCTLContext(DWORD dwMsgAndCertEncodingType
,
310 const BYTE
*pbCtlEncoded
, DWORD cbCtlEncoded
)
312 PCTL_CONTEXT ctl
= NULL
;
315 BYTE
*content
= NULL
;
316 DWORD contentSize
= 0, size
;
317 PCTL_INFO ctlInfo
= NULL
;
319 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType
, pbCtlEncoded
,
322 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType
) != X509_ASN_ENCODING
)
324 SetLastError(E_INVALIDARG
);
327 if (!pbCtlEncoded
|| !cbCtlEncoded
)
329 SetLastError(ERROR_INVALID_DATA
);
332 msg
= CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING
| X509_ASN_ENCODING
, 0, 0,
336 ret
= CryptMsgUpdate(msg
, pbCtlEncoded
, cbCtlEncoded
, TRUE
);
339 SetLastError(ERROR_INVALID_DATA
);
342 /* Check that it's really a CTL */
343 ret
= CryptMsgGetParam(msg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0, NULL
, &size
);
346 char *innerContent
= CryptMemAlloc(size
);
350 ret
= CryptMsgGetParam(msg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0,
351 innerContent
, &size
);
354 if (strcmp(innerContent
, szOID_CTL
))
356 SetLastError(ERROR_INVALID_DATA
);
360 CryptMemFree(innerContent
);
364 SetLastError(ERROR_OUTOFMEMORY
);
370 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, NULL
, &contentSize
);
373 content
= CryptMemAlloc(contentSize
);
376 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, content
,
380 ret
= CryptDecodeObjectEx(dwMsgAndCertEncodingType
, PKCS_CTL
,
381 content
, contentSize
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
382 (BYTE
*)&ctlInfo
, &size
);
385 ctl
= Context_CreateDataContext(sizeof(CTL_CONTEXT
));
388 BYTE
*data
= CryptMemAlloc(cbCtlEncoded
);
392 memcpy(data
, pbCtlEncoded
, cbCtlEncoded
);
393 ctl
->dwMsgAndCertEncodingType
=
394 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
;
395 ctl
->pbCtlEncoded
= data
;
396 ctl
->cbCtlEncoded
= cbCtlEncoded
;
397 ctl
->pCtlInfo
= ctlInfo
;
398 ctl
->hCertStore
= NULL
;
399 ctl
->hCryptMsg
= msg
;
400 ctl
->pbCtlContext
= content
;
401 ctl
->cbCtlContext
= contentSize
;
405 SetLastError(ERROR_OUTOFMEMORY
);
411 SetLastError(ERROR_OUTOFMEMORY
);
419 SetLastError(ERROR_OUTOFMEMORY
);
429 CryptMemFree(content
);
432 return (PCCTL_CONTEXT
)ctl
;
435 PCCTL_CONTEXT WINAPI
CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext
)
437 TRACE("(%p)\n", pCtlContext
);
438 Context_AddRef((void *)pCtlContext
, sizeof(CTL_CONTEXT
));
442 static void CTLDataContext_Free(void *context
)
444 PCTL_CONTEXT ctlContext
= (PCTL_CONTEXT
)context
;
446 CryptMsgClose(ctlContext
->hCryptMsg
);
447 CryptMemFree(ctlContext
->pbCtlEncoded
);
448 CryptMemFree(ctlContext
->pbCtlContext
);
449 LocalFree(ctlContext
->pCtlInfo
);
452 BOOL WINAPI
CertFreeCTLContext(PCCTL_CONTEXT pCTLContext
)
454 TRACE("(%p)\n", pCTLContext
);
457 Context_Release((void *)pCTLContext
, sizeof(CTL_CONTEXT
),
458 CTLDataContext_Free
);
462 DWORD WINAPI
CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext
,
465 PCONTEXT_PROPERTY_LIST properties
= Context_GetProperties(
466 (void *)pCTLContext
, sizeof(CTL_CONTEXT
));
469 TRACE("(%p, %d)\n", pCTLContext
, dwPropId
);
472 ret
= ContextPropertyList_EnumPropIDs(properties
, dwPropId
);
478 static BOOL
CTLContext_SetProperty(PCCTL_CONTEXT context
, DWORD dwPropId
,
479 DWORD dwFlags
, const void *pvData
);
481 static BOOL
CTLContext_GetHashProp(PCCTL_CONTEXT context
, DWORD dwPropId
,
482 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
485 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
489 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
491 ret
= CTLContext_SetProperty(context
, dwPropId
, 0, &blob
);
496 static BOOL
CTLContext_GetProperty(PCCTL_CONTEXT context
, DWORD dwPropId
,
497 void *pvData
, DWORD
*pcbData
)
499 PCONTEXT_PROPERTY_LIST properties
=
500 Context_GetProperties(context
, sizeof(CTL_CONTEXT
));
502 CRYPT_DATA_BLOB blob
;
504 TRACE("(%p, %d, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
507 ret
= ContextPropertyList_FindProperty(properties
, dwPropId
, &blob
);
513 *pcbData
= blob
.cbData
;
514 else if (*pcbData
< blob
.cbData
)
516 SetLastError(ERROR_MORE_DATA
);
517 *pcbData
= blob
.cbData
;
522 memcpy(pvData
, blob
.pbData
, blob
.cbData
);
523 *pcbData
= blob
.cbData
;
528 /* Implicit properties */
531 case CERT_SHA1_HASH_PROP_ID
:
532 ret
= CTLContext_GetHashProp(context
, dwPropId
, CALG_SHA1
,
533 context
->pbCtlEncoded
, context
->cbCtlEncoded
, pvData
, pcbData
);
535 case CERT_MD5_HASH_PROP_ID
:
536 ret
= CTLContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
537 context
->pbCtlEncoded
, context
->cbCtlEncoded
, pvData
, pcbData
);
540 SetLastError(CRYPT_E_NOT_FOUND
);
543 TRACE("returning %d\n", ret
);
547 BOOL WINAPI
CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
548 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
552 TRACE("(%p, %d, %p, %p)\n", pCTLContext
, dwPropId
, pvData
, pcbData
);
557 case CERT_CERT_PROP_ID
:
558 case CERT_CRL_PROP_ID
:
559 case CERT_CTL_PROP_ID
:
560 SetLastError(E_INVALIDARG
);
563 case CERT_ACCESS_STATE_PROP_ID
:
566 *pcbData
= sizeof(DWORD
);
569 else if (*pcbData
< sizeof(DWORD
))
571 SetLastError(ERROR_MORE_DATA
);
572 *pcbData
= sizeof(DWORD
);
577 if (pCTLContext
->hCertStore
)
578 ret
= CertGetStoreProperty(pCTLContext
->hCertStore
, dwPropId
,
581 *(DWORD
*)pvData
= 0;
586 ret
= CTLContext_GetProperty(pCTLContext
, dwPropId
, pvData
,
592 static BOOL
CTLContext_SetProperty(PCCTL_CONTEXT context
, DWORD dwPropId
,
593 DWORD dwFlags
, const void *pvData
)
595 PCONTEXT_PROPERTY_LIST properties
=
596 Context_GetProperties(context
, sizeof(CTL_CONTEXT
));
599 TRACE("(%p, %d, %08x, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
605 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
612 case CERT_AUTO_ENROLL_PROP_ID
:
613 case CERT_CTL_USAGE_PROP_ID
: /* same as CERT_ENHKEY_USAGE_PROP_ID */
614 case CERT_DESCRIPTION_PROP_ID
:
615 case CERT_FRIENDLY_NAME_PROP_ID
:
616 case CERT_HASH_PROP_ID
:
617 case CERT_KEY_IDENTIFIER_PROP_ID
:
618 case CERT_MD5_HASH_PROP_ID
:
619 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
620 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
621 case CERT_PVK_FILE_PROP_ID
:
622 case CERT_SIGNATURE_HASH_PROP_ID
:
623 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
624 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
625 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
626 case CERT_ENROLLMENT_PROP_ID
:
627 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
628 case CERT_RENEWAL_PROP_ID
:
630 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
632 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
633 blob
->pbData
, blob
->cbData
);
636 case CERT_DATE_STAMP_PROP_ID
:
637 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
638 (const BYTE
*)pvData
, sizeof(FILETIME
));
641 FIXME("%d: stub\n", dwPropId
);
645 TRACE("returning %d\n", ret
);
649 BOOL WINAPI
CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext
,
650 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
654 TRACE("(%p, %d, %08x, %p)\n", pCTLContext
, dwPropId
, dwFlags
, pvData
);
656 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
657 * crashes on most of these, I'll be safer.
662 case CERT_ACCESS_STATE_PROP_ID
:
663 case CERT_CERT_PROP_ID
:
664 case CERT_CRL_PROP_ID
:
665 case CERT_CTL_PROP_ID
:
666 SetLastError(E_INVALIDARG
);
669 ret
= CTLContext_SetProperty(pCTLContext
, dwPropId
, dwFlags
, pvData
);
670 TRACE("returning %d\n", ret
);