2 * Copyright 2004-2006 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
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
31 #include "crypt32_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
35 /* Internal version of CertGetCertificateContextProperty that gets properties
36 * directly from the context (or the context it's linked to, depending on its
37 * type.) Doesn't handle special-case properties, since they are handled by
38 * CertGetCertificateContextProperty, and are particular to the store in which
39 * the property exists (which is separate from the context.)
41 static BOOL
CertContext_GetProperty(void *context
, DWORD dwPropId
,
42 void *pvData
, DWORD
*pcbData
);
44 /* Internal version of CertSetCertificateContextProperty that sets properties
45 * directly on the context (or the context it's linked to, depending on its
46 * type.) Doesn't handle special cases, since they're handled by
47 * CertSetCertificateContextProperty anyway.
49 static BOOL
CertContext_SetProperty(void *context
, DWORD dwPropId
,
50 DWORD dwFlags
, const void *pvData
);
52 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
53 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
54 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
56 PCCERT_CONTEXT cert
= CertCreateCertificateContext(dwCertEncodingType
,
57 pbCertEncoded
, cbCertEncoded
);
60 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore
, dwCertEncodingType
,
61 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
65 ret
= CertAddCertificateContextToStore(hCertStore
, cert
,
66 dwAddDisposition
, ppCertContext
);
67 CertFreeCertificateContext(cert
);
74 BOOL WINAPI
CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName
,
75 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
80 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName
), pbCertEncoded
,
83 store
= CertOpenSystemStoreA(0, pszCertStoreName
);
86 ret
= CertAddEncodedCertificateToStore(store
, X509_ASN_ENCODING
,
87 pbCertEncoded
, cbCertEncoded
, CERT_STORE_ADD_USE_EXISTING
, NULL
);
88 CertCloseStore(store
, 0);
93 BOOL WINAPI
CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName
,
94 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
99 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName
), pbCertEncoded
,
102 store
= CertOpenSystemStoreW(0, pszCertStoreName
);
105 ret
= CertAddEncodedCertificateToStore(store
, X509_ASN_ENCODING
,
106 pbCertEncoded
, cbCertEncoded
, CERT_STORE_ADD_USE_EXISTING
, NULL
);
107 CertCloseStore(store
, 0);
112 static void Cert_free(context_t
*context
)
114 cert_t
*cert
= (cert_t
*)context
;
116 CryptMemFree(cert
->ctx
.pbCertEncoded
);
117 LocalFree(cert
->ctx
.pCertInfo
);
120 static const context_vtbl_t cert_vtbl
= {
124 BOOL WINAPI
CertAddCertificateContextToStore(HCERTSTORE hCertStore
,
125 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
126 PCCERT_CONTEXT
*ppStoreContext
)
128 WINECRYPT_CERTSTORE
*store
= hCertStore
;
130 PCCERT_CONTEXT toAdd
= NULL
, existing
= NULL
;
132 TRACE("(%p, %p, %08x, %p)\n", hCertStore
, pCertContext
,
133 dwAddDisposition
, ppStoreContext
);
135 switch (dwAddDisposition
)
137 case CERT_STORE_ADD_ALWAYS
:
139 case CERT_STORE_ADD_NEW
:
140 case CERT_STORE_ADD_REPLACE_EXISTING
:
141 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
:
142 case CERT_STORE_ADD_USE_EXISTING
:
143 case CERT_STORE_ADD_NEWER
:
144 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
:
147 DWORD size
= sizeof(hashToAdd
);
149 ret
= CertGetCertificateContextProperty(pCertContext
, CERT_HASH_PROP_ID
,
153 CRYPT_HASH_BLOB blob
= { sizeof(hashToAdd
), hashToAdd
};
155 existing
= CertFindCertificateInStore(hCertStore
,
156 pCertContext
->dwCertEncodingType
, 0, CERT_FIND_SHA1_HASH
, &blob
,
162 FIXME("Unimplemented add disposition %d\n", dwAddDisposition
);
163 SetLastError(E_INVALIDARG
);
167 switch (dwAddDisposition
)
169 case CERT_STORE_ADD_ALWAYS
:
170 toAdd
= CertDuplicateCertificateContext(pCertContext
);
172 case CERT_STORE_ADD_NEW
:
175 TRACE("found matching certificate, not adding\n");
176 SetLastError(CRYPT_E_EXISTS
);
180 toAdd
= CertDuplicateCertificateContext(pCertContext
);
182 case CERT_STORE_ADD_REPLACE_EXISTING
:
183 toAdd
= CertDuplicateCertificateContext(pCertContext
);
185 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
:
186 toAdd
= CertDuplicateCertificateContext(pCertContext
);
188 Context_CopyProperties(toAdd
, existing
);
190 case CERT_STORE_ADD_USE_EXISTING
:
193 Context_CopyProperties(existing
, pCertContext
);
195 *ppStoreContext
= CertDuplicateCertificateContext(existing
);
198 toAdd
= CertDuplicateCertificateContext(pCertContext
);
200 case CERT_STORE_ADD_NEWER
:
203 if (CompareFileTime(&existing
->pCertInfo
->NotBefore
,
204 &pCertContext
->pCertInfo
->NotBefore
) >= 0)
206 TRACE("existing certificate is newer, not adding\n");
207 SetLastError(CRYPT_E_EXISTS
);
211 toAdd
= CertDuplicateCertificateContext(pCertContext
);
214 toAdd
= CertDuplicateCertificateContext(pCertContext
);
216 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
:
219 if (CompareFileTime(&existing
->pCertInfo
->NotBefore
,
220 &pCertContext
->pCertInfo
->NotBefore
) >= 0)
222 TRACE("existing certificate is newer, not adding\n");
223 SetLastError(CRYPT_E_EXISTS
);
228 toAdd
= CertDuplicateCertificateContext(pCertContext
);
229 Context_CopyProperties(toAdd
, existing
);
233 toAdd
= CertDuplicateCertificateContext(pCertContext
);
240 ret
= store
->vtbl
->certs
.addContext(store
, (void *)toAdd
,
241 (void *)existing
, (const void **)ppStoreContext
);
242 else if (ppStoreContext
)
243 *ppStoreContext
= CertDuplicateCertificateContext(toAdd
);
244 CertFreeCertificateContext(toAdd
);
246 CertFreeCertificateContext(existing
);
248 TRACE("returning %d\n", ret
);
252 BOOL WINAPI
CertAddCertificateLinkToStore(HCERTSTORE hCertStore
,
253 PCCERT_CONTEXT pCertContext
, DWORD dwAddDisposition
,
254 PCCERT_CONTEXT
*ppCertContext
)
257 WINECRYPT_CERTSTORE
*store
= (WINECRYPT_CERTSTORE
*)hCertStore
;
260 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore
, pCertContext
,
261 dwAddDisposition
, ppCertContext
);
262 if (store
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
264 if (store
->type
== StoreTypeCollection
)
266 SetLastError(E_INVALIDARG
);
269 return CertAddCertificateContextToStore(hCertStore
, pCertContext
,
270 dwAddDisposition
, ppCertContext
);
273 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
274 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
276 PCERT_CONTEXT cert
= NULL
;
278 PCERT_INFO certInfo
= NULL
;
281 TRACE("(%08x, %p, %d)\n", dwCertEncodingType
, pbCertEncoded
,
284 if ((dwCertEncodingType
& CERT_ENCODING_TYPE_MASK
) != X509_ASN_ENCODING
)
286 SetLastError(E_INVALIDARG
);
290 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
,
291 pbCertEncoded
, cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
,
297 cert
= Context_CreateDataContext(sizeof(CERT_CONTEXT
), &cert_vtbl
);
300 data
= CryptMemAlloc(cbCertEncoded
);
303 CertFreeCertificateContext(cert
);
307 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
308 cert
->dwCertEncodingType
= dwCertEncodingType
;
309 cert
->pbCertEncoded
= data
;
310 cert
->cbCertEncoded
= cbCertEncoded
;
311 cert
->pCertInfo
= certInfo
;
312 cert
->hCertStore
= &empty_store
;
319 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext
)
321 TRACE("(%p)\n", pCertContext
);
326 Context_AddRef(&cert_from_ptr(pCertContext
)->base
);
330 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
334 TRACE("(%p)\n", pCertContext
);
337 ret
= Context_Release(&cert_from_ptr(pCertContext
)->base
);
341 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
344 CONTEXT_PROPERTY_LIST
*properties
= Context_GetProperties(pCertContext
);
347 TRACE("(%p, %d)\n", pCertContext
, dwPropId
);
350 ret
= ContextPropertyList_EnumPropIDs(properties
, dwPropId
);
356 static BOOL
CertContext_GetHashProp(void *context
, DWORD dwPropId
,
357 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
360 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
364 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
366 ret
= CertContext_SetProperty(context
, dwPropId
, 0, &blob
);
371 static BOOL
CertContext_CopyParam(void *pvData
, DWORD
*pcbData
, const void *pb
,
378 else if (*pcbData
< cb
)
380 SetLastError(ERROR_MORE_DATA
);
386 memcpy(pvData
, pb
, cb
);
392 static BOOL
CertContext_GetProperty(void *context
, DWORD dwPropId
,
393 void *pvData
, DWORD
*pcbData
)
395 PCCERT_CONTEXT pCertContext
= context
;
396 CONTEXT_PROPERTY_LIST
*properties
= Context_GetProperties(context
);
398 CRYPT_DATA_BLOB blob
;
400 TRACE("(%p, %d, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
403 ret
= ContextPropertyList_FindProperty(properties
, dwPropId
, &blob
);
407 ret
= CertContext_CopyParam(pvData
, pcbData
, blob
.pbData
, blob
.cbData
);
410 /* Implicit properties */
413 case CERT_SHA1_HASH_PROP_ID
:
414 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_SHA1
,
415 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
, pvData
,
418 case CERT_MD5_HASH_PROP_ID
:
419 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
420 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
, pvData
,
423 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
424 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
425 pCertContext
->pCertInfo
->Subject
.pbData
,
426 pCertContext
->pCertInfo
->Subject
.cbData
,
429 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
430 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
431 pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
432 pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
,
435 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
436 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
437 pCertContext
->pCertInfo
->SerialNumber
.pbData
,
438 pCertContext
->pCertInfo
->SerialNumber
.cbData
,
441 case CERT_SIGNATURE_HASH_PROP_ID
:
442 ret
= CryptHashToBeSigned(0, pCertContext
->dwCertEncodingType
,
443 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
, pvData
,
447 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
449 ret
= CertContext_SetProperty(context
, dwPropId
, 0, &blob
);
452 case CERT_KEY_IDENTIFIER_PROP_ID
:
454 PCERT_EXTENSION ext
= CertFindExtension(
455 szOID_SUBJECT_KEY_IDENTIFIER
, pCertContext
->pCertInfo
->cExtension
,
456 pCertContext
->pCertInfo
->rgExtension
);
460 CRYPT_DATA_BLOB value
;
461 DWORD size
= sizeof(value
);
463 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
,
464 szOID_SUBJECT_KEY_IDENTIFIER
, ext
->Value
.pbData
,
465 ext
->Value
.cbData
, CRYPT_DECODE_NOCOPY_FLAG
, NULL
, &value
,
469 ret
= CertContext_CopyParam(pvData
, pcbData
, value
.pbData
,
471 CertContext_SetProperty(context
, dwPropId
, 0, &value
);
475 SetLastError(ERROR_INVALID_DATA
);
479 SetLastError(CRYPT_E_NOT_FOUND
);
482 TRACE("returning %d\n", ret
);
486 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info
)
488 DWORD i
, containerLen
, provNameLen
;
489 LPBYTE data
= (LPBYTE
)info
+ sizeof(CRYPT_KEY_PROV_INFO
);
491 info
->pwszContainerName
= (LPWSTR
)data
;
492 containerLen
= (lstrlenW(info
->pwszContainerName
) + 1) * sizeof(WCHAR
);
493 data
+= containerLen
;
495 info
->pwszProvName
= (LPWSTR
)data
;
496 provNameLen
= (lstrlenW(info
->pwszProvName
) + 1) * sizeof(WCHAR
);
499 info
->rgProvParam
= (PCRYPT_KEY_PROV_PARAM
)data
;
500 data
+= info
->cProvParam
* sizeof(CRYPT_KEY_PROV_PARAM
);
502 for (i
= 0; i
< info
->cProvParam
; i
++)
504 info
->rgProvParam
[i
].pbData
= data
;
505 data
+= info
->rgProvParam
[i
].cbData
;
509 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
510 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
514 TRACE("(%p, %d, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
519 case CERT_CERT_PROP_ID
:
520 case CERT_CRL_PROP_ID
:
521 case CERT_CTL_PROP_ID
:
522 SetLastError(E_INVALIDARG
);
525 case CERT_ACCESS_STATE_PROP_ID
:
526 if (pCertContext
->hCertStore
)
527 ret
= CertGetStoreProperty(pCertContext
->hCertStore
, dwPropId
,
533 ret
= CertContext_CopyParam(pvData
, pcbData
, &state
, sizeof(state
));
536 case CERT_KEY_PROV_HANDLE_PROP_ID
:
538 CERT_KEY_CONTEXT keyContext
;
539 DWORD size
= sizeof(keyContext
);
541 ret
= CertContext_GetProperty((void *)pCertContext
,
542 CERT_KEY_CONTEXT_PROP_ID
, &keyContext
, &size
);
544 ret
= CertContext_CopyParam(pvData
, pcbData
, &keyContext
.hCryptProv
,
545 sizeof(keyContext
.hCryptProv
));
548 case CERT_KEY_PROV_INFO_PROP_ID
:
549 ret
= CertContext_GetProperty((void *)pCertContext
, dwPropId
, pvData
,
552 CRYPT_FixKeyProvInfoPointers(pvData
);
555 ret
= CertContext_GetProperty((void *)pCertContext
, dwPropId
, pvData
,
559 TRACE("returning %d\n", ret
);
563 /* Copies key provider info from from into to, where to is assumed to be a
564 * contiguous buffer of memory large enough for from and all its associated
565 * data, but whose pointers are uninitialized.
566 * Upon return, to contains a contiguous copy of from, packed in the following
568 * - CRYPT_KEY_PROV_INFO
569 * - pwszContainerName
571 * - rgProvParam[0]...
573 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to
,
574 const CRYPT_KEY_PROV_INFO
*from
)
577 LPBYTE nextData
= (LPBYTE
)to
+ sizeof(CRYPT_KEY_PROV_INFO
);
579 if (from
->pwszContainerName
)
581 to
->pwszContainerName
= (LPWSTR
)nextData
;
582 lstrcpyW(to
->pwszContainerName
, from
->pwszContainerName
);
583 nextData
+= (lstrlenW(from
->pwszContainerName
) + 1) * sizeof(WCHAR
);
586 to
->pwszContainerName
= NULL
;
587 if (from
->pwszProvName
)
589 to
->pwszProvName
= (LPWSTR
)nextData
;
590 lstrcpyW(to
->pwszProvName
, from
->pwszProvName
);
591 nextData
+= (lstrlenW(from
->pwszProvName
) + 1) * sizeof(WCHAR
);
594 to
->pwszProvName
= NULL
;
595 to
->dwProvType
= from
->dwProvType
;
596 to
->dwFlags
= from
->dwFlags
;
597 to
->cProvParam
= from
->cProvParam
;
598 to
->rgProvParam
= (PCRYPT_KEY_PROV_PARAM
)nextData
;
599 nextData
+= to
->cProvParam
* sizeof(CRYPT_KEY_PROV_PARAM
);
600 to
->dwKeySpec
= from
->dwKeySpec
;
601 for (i
= 0; i
< to
->cProvParam
; i
++)
603 memcpy(&to
->rgProvParam
[i
], &from
->rgProvParam
[i
],
604 sizeof(CRYPT_KEY_PROV_PARAM
));
605 to
->rgProvParam
[i
].pbData
= nextData
;
606 memcpy(to
->rgProvParam
[i
].pbData
, from
->rgProvParam
[i
].pbData
,
607 from
->rgProvParam
[i
].cbData
);
608 nextData
+= from
->rgProvParam
[i
].cbData
;
612 static BOOL
CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST
*properties
,
613 const CRYPT_KEY_PROV_INFO
*info
)
617 DWORD size
= sizeof(CRYPT_KEY_PROV_INFO
), i
, containerSize
, provNameSize
;
619 if (info
->pwszContainerName
)
620 containerSize
= (lstrlenW(info
->pwszContainerName
) + 1) * sizeof(WCHAR
);
623 if (info
->pwszProvName
)
624 provNameSize
= (lstrlenW(info
->pwszProvName
) + 1) * sizeof(WCHAR
);
627 size
+= containerSize
+ provNameSize
;
628 for (i
= 0; i
< info
->cProvParam
; i
++)
629 size
+= sizeof(CRYPT_KEY_PROV_PARAM
) + info
->rgProvParam
[i
].cbData
;
630 buf
= CryptMemAlloc(size
);
633 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO
)buf
, info
);
634 ret
= ContextPropertyList_SetProperty(properties
,
635 CERT_KEY_PROV_INFO_PROP_ID
, buf
, size
);
643 static BOOL
CertContext_SetProperty(void *context
, DWORD dwPropId
,
644 DWORD dwFlags
, const void *pvData
)
646 CONTEXT_PROPERTY_LIST
*properties
= Context_GetProperties(context
);
649 TRACE("(%p, %d, %08x, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
657 case CERT_AUTO_ENROLL_PROP_ID
:
658 case CERT_CTL_USAGE_PROP_ID
: /* same as CERT_ENHKEY_USAGE_PROP_ID */
659 case CERT_DESCRIPTION_PROP_ID
:
660 case CERT_FRIENDLY_NAME_PROP_ID
:
661 case CERT_HASH_PROP_ID
:
662 case CERT_KEY_IDENTIFIER_PROP_ID
:
663 case CERT_MD5_HASH_PROP_ID
:
664 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
665 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
666 case CERT_PVK_FILE_PROP_ID
:
667 case CERT_SIGNATURE_HASH_PROP_ID
:
668 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
669 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
670 case CERT_EXTENDED_ERROR_INFO_PROP_ID
:
671 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
672 case CERT_ENROLLMENT_PROP_ID
:
673 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
674 case CERT_RENEWAL_PROP_ID
:
678 const CRYPT_DATA_BLOB
*blob
= pvData
;
680 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
681 blob
->pbData
, blob
->cbData
);
685 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
690 case CERT_DATE_STAMP_PROP_ID
:
692 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
693 pvData
, sizeof(FILETIME
));
696 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
700 case CERT_KEY_CONTEXT_PROP_ID
:
704 const CERT_KEY_CONTEXT
*keyContext
= pvData
;
706 if (keyContext
->cbSize
!= sizeof(CERT_KEY_CONTEXT
))
708 SetLastError(E_INVALIDARG
);
712 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
713 (const BYTE
*)keyContext
, keyContext
->cbSize
);
717 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
722 case CERT_KEY_PROV_INFO_PROP_ID
:
724 ret
= CertContext_SetKeyProvInfoProperty(properties
, pvData
);
727 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
731 case CERT_KEY_PROV_HANDLE_PROP_ID
:
733 CERT_KEY_CONTEXT keyContext
;
734 DWORD size
= sizeof(keyContext
);
736 ret
= CertContext_GetProperty(context
, CERT_KEY_CONTEXT_PROP_ID
,
740 if (!(dwFlags
& CERT_STORE_NO_CRYPT_RELEASE_FLAG
))
741 CryptReleaseContext(keyContext
.hCryptProv
, 0);
743 keyContext
.cbSize
= sizeof(keyContext
);
745 keyContext
.hCryptProv
= *(const HCRYPTPROV
*)pvData
;
748 keyContext
.hCryptProv
= 0;
749 keyContext
.dwKeySpec
= AT_SIGNATURE
;
751 ret
= CertContext_SetProperty(context
, CERT_KEY_CONTEXT_PROP_ID
,
756 FIXME("%d: stub\n", dwPropId
);
760 TRACE("returning %d\n", ret
);
764 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
765 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
769 TRACE("(%p, %d, %08x, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
771 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
772 * crashes on most of these, I'll be safer.
777 case CERT_ACCESS_STATE_PROP_ID
:
778 case CERT_CERT_PROP_ID
:
779 case CERT_CRL_PROP_ID
:
780 case CERT_CTL_PROP_ID
:
781 SetLastError(E_INVALIDARG
);
784 ret
= CertContext_SetProperty((void *)pCertContext
, dwPropId
, dwFlags
,
786 TRACE("returning %d\n", ret
);
790 /* Acquires the private key using the key provider info, retrieving info from
791 * the certificate if info is NULL. The acquired provider is returned in
792 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
794 static BOOL
CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert
,
795 PCRYPT_KEY_PROV_INFO info
, HCRYPTPROV
*phCryptProv
, DWORD
*pdwKeySpec
)
798 BOOL allocated
= FALSE
, ret
= TRUE
;
802 ret
= CertGetCertificateContextProperty(pCert
,
803 CERT_KEY_PROV_INFO_PROP_ID
, 0, &size
);
806 info
= HeapAlloc(GetProcessHeap(), 0, size
);
809 ret
= CertGetCertificateContextProperty(pCert
,
810 CERT_KEY_PROV_INFO_PROP_ID
, info
, &size
);
815 SetLastError(ERROR_OUTOFMEMORY
);
820 SetLastError(CRYPT_E_NO_KEY_PROPERTY
);
824 ret
= CryptAcquireContextW(phCryptProv
, info
->pwszContainerName
,
825 info
->pwszProvName
, info
->dwProvType
, 0);
830 for (i
= 0; i
< info
->cProvParam
; i
++)
832 CryptSetProvParam(*phCryptProv
,
833 info
->rgProvParam
[i
].dwParam
, info
->rgProvParam
[i
].pbData
,
834 info
->rgProvParam
[i
].dwFlags
);
836 *pdwKeySpec
= info
->dwKeySpec
;
839 SetLastError(CRYPT_E_NO_KEY_PROPERTY
);
842 HeapFree(GetProcessHeap(), 0, info
);
846 BOOL WINAPI
CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert
,
847 DWORD dwFlags
, void *pvReserved
, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE
*phCryptProv
,
848 DWORD
*pdwKeySpec
, BOOL
*pfCallerFreeProv
)
850 BOOL ret
= FALSE
, cache
= FALSE
;
851 PCRYPT_KEY_PROV_INFO info
= NULL
;
852 CERT_KEY_CONTEXT keyContext
;
855 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert
, dwFlags
, pvReserved
,
856 phCryptProv
, pdwKeySpec
, pfCallerFreeProv
);
858 if (dwFlags
& CRYPT_ACQUIRE_USE_PROV_INFO_FLAG
)
862 ret
= CertGetCertificateContextProperty(pCert
,
863 CERT_KEY_PROV_INFO_PROP_ID
, 0, &size
);
866 info
= HeapAlloc(GetProcessHeap(), 0, size
);
867 ret
= CertGetCertificateContextProperty(pCert
,
868 CERT_KEY_PROV_INFO_PROP_ID
, info
, &size
);
870 cache
= info
->dwFlags
& CERT_SET_KEY_CONTEXT_PROP_ID
;
873 else if (dwFlags
& CRYPT_ACQUIRE_CACHE_FLAG
)
878 size
= sizeof(keyContext
);
879 ret
= CertGetCertificateContextProperty(pCert
, CERT_KEY_CONTEXT_PROP_ID
,
883 *phCryptProv
= keyContext
.hCryptProv
;
885 *pdwKeySpec
= keyContext
.dwKeySpec
;
886 if (pfCallerFreeProv
)
887 *pfCallerFreeProv
= !cache
;
892 ret
= CRYPT_AcquirePrivateKeyFromProvInfo(pCert
, info
,
893 &keyContext
.hCryptProv
, &keyContext
.dwKeySpec
);
896 *phCryptProv
= keyContext
.hCryptProv
;
898 *pdwKeySpec
= keyContext
.dwKeySpec
;
901 keyContext
.cbSize
= sizeof(keyContext
);
902 if (CertSetCertificateContextProperty(pCert
,
903 CERT_KEY_CONTEXT_PROP_ID
, 0, &keyContext
))
905 if (pfCallerFreeProv
)
906 *pfCallerFreeProv
= FALSE
;
911 if (pfCallerFreeProv
)
912 *pfCallerFreeProv
= TRUE
;
916 HeapFree(GetProcessHeap(), 0, info
);
920 static BOOL
key_prov_info_matches_cert(PCCERT_CONTEXT pCert
,
921 const CRYPT_KEY_PROV_INFO
*keyProvInfo
)
924 BOOL matches
= FALSE
;
926 if (CryptAcquireContextW(&csp
, keyProvInfo
->pwszContainerName
,
927 keyProvInfo
->pwszProvName
, keyProvInfo
->dwProvType
, keyProvInfo
->dwFlags
))
931 /* Need to sign something to verify the sig. What to sign? Why not
932 * the certificate itself?
934 if (CryptSignAndEncodeCertificate(csp
, AT_SIGNATURE
,
935 pCert
->dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
, pCert
->pCertInfo
,
936 &pCert
->pCertInfo
->SignatureAlgorithm
, NULL
, NULL
, &size
))
938 BYTE
*certEncoded
= CryptMemAlloc(size
);
942 if (CryptSignAndEncodeCertificate(csp
, AT_SIGNATURE
,
943 pCert
->dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
,
944 pCert
->pCertInfo
, &pCert
->pCertInfo
->SignatureAlgorithm
,
945 NULL
, certEncoded
, &size
))
947 if (size
== pCert
->cbCertEncoded
&&
948 !memcmp(certEncoded
, pCert
->pbCertEncoded
, size
))
951 CryptMemFree(certEncoded
);
954 CryptReleaseContext(csp
, 0);
959 static BOOL
container_matches_cert(PCCERT_CONTEXT pCert
, LPCSTR container
,
960 CRYPT_KEY_PROV_INFO
*keyProvInfo
)
962 CRYPT_KEY_PROV_INFO copy
;
963 WCHAR containerW
[MAX_PATH
];
964 BOOL matches
= FALSE
;
966 MultiByteToWideChar(CP_ACP
, 0, container
, -1,
967 containerW
, sizeof(containerW
) / sizeof(containerW
[0]));
968 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
969 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
973 copy
.pwszContainerName
= containerW
;
974 matches
= key_prov_info_matches_cert(pCert
, ©
);
977 keyProvInfo
->pwszContainerName
=
978 CryptMemAlloc((strlenW(containerW
) + 1) * sizeof(WCHAR
));
979 if (keyProvInfo
->pwszContainerName
)
981 strcpyW(keyProvInfo
->pwszContainerName
, containerW
);
982 keyProvInfo
->dwKeySpec
= AT_SIGNATURE
;
990 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
991 * private key matches pCert's public key. Upon success, updates keyProvInfo
992 * with the matching container's info (free keyProvInfo.pwszContainerName upon
994 * Returns TRUE if found, FALSE if not.
996 static BOOL
find_key_prov_info_in_provider(PCCERT_CONTEXT pCert
,
997 CRYPT_KEY_PROV_INFO
*keyProvInfo
)
999 HCRYPTPROV defProvider
;
1000 BOOL ret
, found
= FALSE
;
1001 char containerA
[MAX_PATH
];
1003 assert(keyProvInfo
->pwszContainerName
== NULL
);
1004 if ((ret
= CryptAcquireContextW(&defProvider
, NULL
,
1005 keyProvInfo
->pwszProvName
, keyProvInfo
->dwProvType
,
1006 keyProvInfo
->dwFlags
| CRYPT_VERIFYCONTEXT
)))
1008 DWORD enumFlags
= keyProvInfo
->dwFlags
| CRYPT_FIRST
;
1010 while (ret
&& !found
)
1012 DWORD size
= sizeof(containerA
);
1014 ret
= CryptGetProvParam(defProvider
, PP_ENUMCONTAINERS
,
1015 (BYTE
*)containerA
, &size
, enumFlags
);
1017 found
= container_matches_cert(pCert
, containerA
, keyProvInfo
);
1018 if (enumFlags
& CRYPT_FIRST
)
1020 enumFlags
&= ~CRYPT_FIRST
;
1021 enumFlags
|= CRYPT_NEXT
;
1024 CryptReleaseContext(defProvider
, 0);
1029 static BOOL
find_matching_provider(PCCERT_CONTEXT pCert
, DWORD dwFlags
)
1031 BOOL found
= FALSE
, ret
= TRUE
;
1032 DWORD index
= 0, cbProvName
= 0;
1033 CRYPT_KEY_PROV_INFO keyProvInfo
;
1035 TRACE("(%p, %08x)\n", pCert
, dwFlags
);
1037 memset(&keyProvInfo
, 0, sizeof(keyProvInfo
));
1038 while (ret
&& !found
)
1042 ret
= CryptEnumProvidersW(index
, NULL
, 0, &keyProvInfo
.dwProvType
,
1046 if (size
<= cbProvName
)
1047 ret
= CryptEnumProvidersW(index
, NULL
, 0,
1048 &keyProvInfo
.dwProvType
, keyProvInfo
.pwszProvName
, &size
);
1051 CryptMemFree(keyProvInfo
.pwszProvName
);
1052 keyProvInfo
.pwszProvName
= CryptMemAlloc(size
);
1053 if (keyProvInfo
.pwszProvName
)
1056 ret
= CryptEnumProvidersW(index
, NULL
, 0,
1057 &keyProvInfo
.dwProvType
, keyProvInfo
.pwszProvName
, &size
);
1060 if (dwFlags
& CRYPT_FIND_SILENT_KEYSET_FLAG
)
1061 keyProvInfo
.dwFlags
|= CRYPT_SILENT
;
1062 if (dwFlags
& CRYPT_FIND_USER_KEYSET_FLAG
||
1063 !(dwFlags
& (CRYPT_FIND_USER_KEYSET_FLAG
|
1064 CRYPT_FIND_MACHINE_KEYSET_FLAG
)))
1066 keyProvInfo
.dwFlags
|= CRYPT_USER_KEYSET
;
1067 found
= find_key_prov_info_in_provider(pCert
,
1072 if (dwFlags
& CRYPT_FIND_MACHINE_KEYSET_FLAG
||
1073 !(dwFlags
& (CRYPT_FIND_USER_KEYSET_FLAG
|
1074 CRYPT_FIND_MACHINE_KEYSET_FLAG
)))
1076 keyProvInfo
.dwFlags
&= ~CRYPT_USER_KEYSET
;
1077 keyProvInfo
.dwFlags
|= CRYPT_MACHINE_KEYSET
;
1078 found
= find_key_prov_info_in_provider(pCert
,
1091 CertSetCertificateContextProperty(pCert
, CERT_KEY_PROV_INFO_PROP_ID
,
1093 CryptMemFree(keyProvInfo
.pwszProvName
);
1094 CryptMemFree(keyProvInfo
.pwszContainerName
);
1098 static BOOL
cert_prov_info_matches_cert(PCCERT_CONTEXT pCert
)
1100 BOOL matches
= FALSE
;
1103 if (CertGetCertificateContextProperty(pCert
, CERT_KEY_PROV_INFO_PROP_ID
,
1106 CRYPT_KEY_PROV_INFO
*keyProvInfo
= CryptMemAlloc(size
);
1110 if (CertGetCertificateContextProperty(pCert
,
1111 CERT_KEY_PROV_INFO_PROP_ID
, keyProvInfo
, &size
))
1112 matches
= key_prov_info_matches_cert(pCert
, keyProvInfo
);
1113 CryptMemFree(keyProvInfo
);
1119 BOOL WINAPI
CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert
,
1120 DWORD dwFlags
, void *pvReserved
)
1122 BOOL matches
= FALSE
;
1124 TRACE("(%p, %08x, %p)\n", pCert
, dwFlags
, pvReserved
);
1126 matches
= cert_prov_info_matches_cert(pCert
);
1128 matches
= find_matching_provider(pCert
, dwFlags
);
1132 BOOL WINAPI
CertCompareCertificate(DWORD dwCertEncodingType
,
1133 PCERT_INFO pCertId1
, PCERT_INFO pCertId2
)
1137 TRACE("(%08x, %p, %p)\n", dwCertEncodingType
, pCertId1
, pCertId2
);
1139 ret
= CertCompareCertificateName(dwCertEncodingType
, &pCertId1
->Issuer
,
1140 &pCertId2
->Issuer
) && CertCompareIntegerBlob(&pCertId1
->SerialNumber
,
1141 &pCertId2
->SerialNumber
);
1142 TRACE("returning %d\n", ret
);
1146 BOOL WINAPI
CertCompareCertificateName(DWORD dwCertEncodingType
,
1147 PCERT_NAME_BLOB pCertName1
, PCERT_NAME_BLOB pCertName2
)
1151 TRACE("(%08x, %p, %p)\n", dwCertEncodingType
, pCertName1
, pCertName2
);
1153 if (pCertName1
->cbData
== pCertName2
->cbData
)
1155 if (pCertName1
->cbData
)
1156 ret
= !memcmp(pCertName1
->pbData
, pCertName2
->pbData
,
1157 pCertName1
->cbData
);
1163 TRACE("returning %d\n", ret
);
1167 /* Returns the number of significant bytes in pInt, where a byte is
1168 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
1169 * for negative numbers. pInt is assumed to be little-endian.
1171 static DWORD
CRYPT_significantBytes(const CRYPT_INTEGER_BLOB
*pInt
)
1173 DWORD ret
= pInt
->cbData
;
1177 if (pInt
->pbData
[ret
- 2] <= 0x7f && pInt
->pbData
[ret
- 1] == 0)
1179 else if (pInt
->pbData
[ret
- 2] >= 0x80 && pInt
->pbData
[ret
- 1] == 0xff)
1187 BOOL WINAPI
CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1
,
1188 PCRYPT_INTEGER_BLOB pInt2
)
1193 TRACE("(%p, %p)\n", pInt1
, pInt2
);
1195 cb1
= CRYPT_significantBytes(pInt1
);
1196 cb2
= CRYPT_significantBytes(pInt2
);
1200 ret
= !memcmp(pInt1
->pbData
, pInt2
->pbData
, cb1
);
1206 TRACE("returning %d\n", ret
);
1210 BOOL WINAPI
CertComparePublicKeyInfo(DWORD dwCertEncodingType
,
1211 PCERT_PUBLIC_KEY_INFO pPublicKey1
, PCERT_PUBLIC_KEY_INFO pPublicKey2
)
1215 TRACE("(%08x, %p, %p)\n", dwCertEncodingType
, pPublicKey1
, pPublicKey2
);
1217 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType
))
1219 case 0: /* Seems to mean "raw binary bits" */
1220 if (pPublicKey1
->PublicKey
.cbData
== pPublicKey2
->PublicKey
.cbData
&&
1221 pPublicKey1
->PublicKey
.cUnusedBits
== pPublicKey2
->PublicKey
.cUnusedBits
)
1223 if (pPublicKey2
->PublicKey
.cbData
)
1224 ret
= !memcmp(pPublicKey1
->PublicKey
.pbData
,
1225 pPublicKey2
->PublicKey
.pbData
, pPublicKey1
->PublicKey
.cbData
);
1233 WARN("Unknown encoding type %08x\n", dwCertEncodingType
);
1235 case X509_ASN_ENCODING
:
1237 BLOBHEADER
*pblob1
, *pblob2
;
1240 if (CryptDecodeObject(dwCertEncodingType
, RSA_CSP_PUBLICKEYBLOB
,
1241 pPublicKey1
->PublicKey
.pbData
, pPublicKey1
->PublicKey
.cbData
,
1244 pblob1
= CryptMemAlloc(length
);
1245 if (CryptDecodeObject(dwCertEncodingType
, RSA_CSP_PUBLICKEYBLOB
,
1246 pPublicKey1
->PublicKey
.pbData
, pPublicKey1
->PublicKey
.cbData
,
1247 0, pblob1
, &length
))
1249 if (CryptDecodeObject(dwCertEncodingType
, RSA_CSP_PUBLICKEYBLOB
,
1250 pPublicKey2
->PublicKey
.pbData
, pPublicKey2
->PublicKey
.cbData
,
1253 pblob2
= CryptMemAlloc(length
);
1254 if (CryptDecodeObject(dwCertEncodingType
, RSA_CSP_PUBLICKEYBLOB
,
1255 pPublicKey2
->PublicKey
.pbData
, pPublicKey2
->PublicKey
.cbData
,
1256 0, pblob2
, &length
))
1258 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1259 RSAPUBKEY
*pk1
= (LPVOID
)(pblob1
+ 1),
1260 *pk2
= (LPVOID
)(pblob2
+ 1);
1261 ret
= (pk1
->bitlen
== pk2
->bitlen
) && (pk1
->pubexp
== pk2
->pubexp
)
1262 && !memcmp(pk1
+ 1, pk2
+ 1, pk1
->bitlen
/8);
1264 CryptMemFree(pblob2
);
1267 CryptMemFree(pblob1
);
1276 DWORD WINAPI
CertGetPublicKeyLength(DWORD dwCertEncodingType
,
1277 PCERT_PUBLIC_KEY_INFO pPublicKey
)
1281 TRACE("(%08x, %p)\n", dwCertEncodingType
, pPublicKey
);
1283 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType
) != X509_ASN_ENCODING
)
1285 SetLastError(ERROR_FILE_NOT_FOUND
);
1288 if (pPublicKey
->Algorithm
.pszObjId
&&
1289 !strcmp(pPublicKey
->Algorithm
.pszObjId
, szOID_RSA_DH
))
1291 FIXME("unimplemented for DH public keys\n");
1292 SetLastError(CRYPT_E_ASN1_BADTAG
);
1298 BOOL ret
= CryptDecodeObjectEx(dwCertEncodingType
,
1299 RSA_CSP_PUBLICKEYBLOB
, pPublicKey
->PublicKey
.pbData
,
1300 pPublicKey
->PublicKey
.cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, &buf
,
1305 RSAPUBKEY
*rsaPubKey
= (RSAPUBKEY
*)(buf
+ sizeof(BLOBHEADER
));
1307 len
= rsaPubKey
->bitlen
;
1314 typedef BOOL (*CertCompareFunc
)(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1315 DWORD dwFlags
, const void *pvPara
);
1317 static BOOL
compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1318 DWORD dwFlags
, const void *pvPara
)
1322 DWORD size
= sizeof(hash
);
1324 ret
= CertGetCertificateContextProperty(pCertContext
,
1325 CERT_MD5_HASH_PROP_ID
, hash
, &size
);
1328 const CRYPT_HASH_BLOB
*pHash
= pvPara
;
1330 if (size
== pHash
->cbData
)
1331 ret
= !memcmp(pHash
->pbData
, hash
, size
);
1338 static BOOL
compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1339 DWORD dwFlags
, const void *pvPara
)
1343 DWORD size
= sizeof(hash
);
1345 ret
= CertGetCertificateContextProperty(pCertContext
,
1346 CERT_SHA1_HASH_PROP_ID
, hash
, &size
);
1349 const CRYPT_HASH_BLOB
*pHash
= pvPara
;
1351 if (size
== pHash
->cbData
)
1352 ret
= !memcmp(pHash
->pbData
, hash
, size
);
1359 static BOOL
compare_cert_by_name(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1360 DWORD dwFlags
, const void *pvPara
)
1362 CERT_NAME_BLOB
*blob
= (CERT_NAME_BLOB
*)pvPara
, *toCompare
;
1365 if (dwType
& CERT_INFO_SUBJECT_FLAG
)
1366 toCompare
= &pCertContext
->pCertInfo
->Subject
;
1368 toCompare
= &pCertContext
->pCertInfo
->Issuer
;
1369 ret
= CertCompareCertificateName(pCertContext
->dwCertEncodingType
,
1374 static BOOL
compare_cert_by_public_key(PCCERT_CONTEXT pCertContext
,
1375 DWORD dwType
, DWORD dwFlags
, const void *pvPara
)
1377 CERT_PUBLIC_KEY_INFO
*publicKey
= (CERT_PUBLIC_KEY_INFO
*)pvPara
;
1380 ret
= CertComparePublicKeyInfo(pCertContext
->dwCertEncodingType
,
1381 &pCertContext
->pCertInfo
->SubjectPublicKeyInfo
, publicKey
);
1385 static BOOL
compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext
,
1386 DWORD dwType
, DWORD dwFlags
, const void *pvPara
)
1388 CERT_INFO
*pCertInfo
= (CERT_INFO
*)pvPara
;
1391 /* Matching serial number and subject match.. */
1392 ret
= CertCompareCertificateName(pCertContext
->dwCertEncodingType
,
1393 &pCertContext
->pCertInfo
->Subject
, &pCertInfo
->Issuer
);
1395 ret
= CertCompareIntegerBlob(&pCertContext
->pCertInfo
->SerialNumber
,
1396 &pCertInfo
->SerialNumber
);
1399 /* failing that, if the serial number and issuer match, we match */
1400 ret
= CertCompareIntegerBlob(&pCertContext
->pCertInfo
->SerialNumber
,
1401 &pCertInfo
->SerialNumber
);
1403 ret
= CertCompareCertificateName(pCertContext
->dwCertEncodingType
,
1404 &pCertContext
->pCertInfo
->Issuer
, &pCertInfo
->Issuer
);
1406 TRACE("returning %d\n", ret
);
1410 static BOOL
compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1411 DWORD dwFlags
, const void *pvPara
)
1413 CERT_ID
*id
= (CERT_ID
*)pvPara
;
1416 switch (id
->dwIdChoice
)
1418 case CERT_ID_ISSUER_SERIAL_NUMBER
:
1419 ret
= CertCompareCertificateName(pCertContext
->dwCertEncodingType
,
1420 &pCertContext
->pCertInfo
->Issuer
, &id
->u
.IssuerSerialNumber
.Issuer
);
1422 ret
= CertCompareIntegerBlob(&pCertContext
->pCertInfo
->SerialNumber
,
1423 &id
->u
.IssuerSerialNumber
.SerialNumber
);
1425 case CERT_ID_SHA1_HASH
:
1426 ret
= compare_cert_by_sha1_hash(pCertContext
, dwType
, dwFlags
,
1429 case CERT_ID_KEY_IDENTIFIER
:
1433 ret
= CertGetCertificateContextProperty(pCertContext
,
1434 CERT_KEY_IDENTIFIER_PROP_ID
, NULL
, &size
);
1435 if (ret
&& size
== id
->u
.KeyId
.cbData
)
1437 LPBYTE buf
= CryptMemAlloc(size
);
1441 CertGetCertificateContextProperty(pCertContext
,
1442 CERT_KEY_IDENTIFIER_PROP_ID
, buf
, &size
);
1443 ret
= !memcmp(buf
, id
->u
.KeyId
.pbData
, size
);
1458 static BOOL
compare_existing_cert(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1459 DWORD dwFlags
, const void *pvPara
)
1461 PCCERT_CONTEXT toCompare
= pvPara
;
1462 return CertCompareCertificate(pCertContext
->dwCertEncodingType
,
1463 pCertContext
->pCertInfo
, toCompare
->pCertInfo
);
1466 static BOOL
compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
1467 DWORD dwFlags
, const void *pvPara
)
1469 const CRYPT_HASH_BLOB
*hash
= pvPara
;
1473 ret
= CertGetCertificateContextProperty(pCertContext
,
1474 CERT_SIGNATURE_HASH_PROP_ID
, NULL
, &size
);
1475 if (ret
&& size
== hash
->cbData
)
1477 LPBYTE buf
= CryptMemAlloc(size
);
1481 CertGetCertificateContextProperty(pCertContext
,
1482 CERT_SIGNATURE_HASH_PROP_ID
, buf
, &size
);
1483 ret
= !memcmp(buf
, hash
->pbData
, size
);
1492 static inline PCCERT_CONTEXT
cert_compare_certs_in_store(HCERTSTORE store
,
1493 PCCERT_CONTEXT prev
, CertCompareFunc compare
, DWORD dwType
, DWORD dwFlags
,
1496 BOOL matches
= FALSE
;
1501 ret
= CertEnumCertificatesInStore(store
, ret
);
1503 matches
= compare(ret
, dwType
, dwFlags
, pvPara
);
1504 } while (ret
!= NULL
&& !matches
);
1508 typedef PCCERT_CONTEXT (*CertFindFunc
)(HCERTSTORE store
, DWORD dwType
,
1509 DWORD dwFlags
, const void *pvPara
, PCCERT_CONTEXT prev
);
1511 static PCCERT_CONTEXT
find_cert_any(HCERTSTORE store
, DWORD dwType
,
1512 DWORD dwFlags
, const void *pvPara
, PCCERT_CONTEXT prev
)
1514 return CertEnumCertificatesInStore(store
, prev
);
1517 static PCCERT_CONTEXT
find_cert_by_issuer(HCERTSTORE store
, DWORD dwType
,
1518 DWORD dwFlags
, const void *pvPara
, PCCERT_CONTEXT prev
)
1521 PCCERT_CONTEXT found
= NULL
, subject
= pvPara
;
1522 PCERT_EXTENSION ext
;
1525 if ((ext
= CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER
,
1526 subject
->pCertInfo
->cExtension
, subject
->pCertInfo
->rgExtension
)))
1528 CERT_AUTHORITY_KEY_ID_INFO
*info
;
1530 ret
= CryptDecodeObjectEx(subject
->dwCertEncodingType
,
1531 X509_AUTHORITY_KEY_ID
, ext
->Value
.pbData
, ext
->Value
.cbData
,
1532 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1538 if (info
->CertIssuer
.cbData
&& info
->CertSerialNumber
.cbData
)
1540 id
.dwIdChoice
= CERT_ID_ISSUER_SERIAL_NUMBER
;
1541 memcpy(&id
.u
.IssuerSerialNumber
.Issuer
, &info
->CertIssuer
,
1542 sizeof(CERT_NAME_BLOB
));
1543 memcpy(&id
.u
.IssuerSerialNumber
.SerialNumber
,
1544 &info
->CertSerialNumber
, sizeof(CRYPT_INTEGER_BLOB
));
1546 else if (info
->KeyId
.cbData
)
1548 id
.dwIdChoice
= CERT_ID_KEY_IDENTIFIER
;
1549 memcpy(&id
.u
.KeyId
, &info
->KeyId
, sizeof(CRYPT_HASH_BLOB
));
1554 found
= cert_compare_certs_in_store(store
, prev
,
1555 compare_cert_by_cert_id
, dwType
, dwFlags
, &id
);
1559 else if ((ext
= CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2
,
1560 subject
->pCertInfo
->cExtension
, subject
->pCertInfo
->rgExtension
)))
1562 CERT_AUTHORITY_KEY_ID2_INFO
*info
;
1564 ret
= CryptDecodeObjectEx(subject
->dwCertEncodingType
,
1565 X509_AUTHORITY_KEY_ID2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
1566 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1572 if (info
->AuthorityCertIssuer
.cAltEntry
&&
1573 info
->AuthorityCertSerialNumber
.cbData
)
1575 PCERT_ALT_NAME_ENTRY directoryName
= NULL
;
1578 for (i
= 0; !directoryName
&&
1579 i
< info
->AuthorityCertIssuer
.cAltEntry
; i
++)
1580 if (info
->AuthorityCertIssuer
.rgAltEntry
[i
].dwAltNameChoice
1581 == CERT_ALT_NAME_DIRECTORY_NAME
)
1583 &info
->AuthorityCertIssuer
.rgAltEntry
[i
];
1586 id
.dwIdChoice
= CERT_ID_ISSUER_SERIAL_NUMBER
;
1587 memcpy(&id
.u
.IssuerSerialNumber
.Issuer
,
1588 &directoryName
->u
.DirectoryName
, sizeof(CERT_NAME_BLOB
));
1589 memcpy(&id
.u
.IssuerSerialNumber
.SerialNumber
,
1590 &info
->AuthorityCertSerialNumber
,
1591 sizeof(CRYPT_INTEGER_BLOB
));
1595 FIXME("no supported name type in authority key id2\n");
1599 else if (info
->KeyId
.cbData
)
1601 id
.dwIdChoice
= CERT_ID_KEY_IDENTIFIER
;
1602 memcpy(&id
.u
.KeyId
, &info
->KeyId
, sizeof(CRYPT_HASH_BLOB
));
1607 found
= cert_compare_certs_in_store(store
, prev
,
1608 compare_cert_by_cert_id
, dwType
, dwFlags
, &id
);
1613 found
= cert_compare_certs_in_store(store
, prev
,
1614 compare_cert_by_name
, CERT_COMPARE_NAME
| CERT_COMPARE_SUBJECT_CERT
,
1615 dwFlags
, &subject
->pCertInfo
->Issuer
);
1619 static BOOL
compare_cert_by_name_str(PCCERT_CONTEXT pCertContext
,
1620 DWORD dwType
, DWORD dwFlags
, const void *pvPara
)
1622 PCERT_NAME_BLOB name
;
1626 if (dwType
& CERT_INFO_SUBJECT_FLAG
)
1627 name
= &pCertContext
->pCertInfo
->Subject
;
1629 name
= &pCertContext
->pCertInfo
->Issuer
;
1630 len
= CertNameToStrW(pCertContext
->dwCertEncodingType
, name
,
1631 CERT_SIMPLE_NAME_STR
, NULL
, 0);
1634 LPWSTR str
= CryptMemAlloc(len
* sizeof(WCHAR
));
1640 CertNameToStrW(pCertContext
->dwCertEncodingType
, name
,
1641 CERT_SIMPLE_NAME_STR
, str
, len
);
1642 for (ptr
= str
; *ptr
; ptr
++)
1643 *ptr
= tolowerW(*ptr
);
1644 if (strstrW(str
, pvPara
))
1652 static PCCERT_CONTEXT
find_cert_by_name_str_a(HCERTSTORE store
, DWORD dwType
,
1653 DWORD dwFlags
, const void *pvPara
, PCCERT_CONTEXT prev
)
1655 PCCERT_CONTEXT found
= NULL
;
1657 TRACE("%s\n", debugstr_a(pvPara
));
1661 int len
= MultiByteToWideChar(CP_ACP
, 0, pvPara
, -1, NULL
, 0);
1662 LPWSTR str
= CryptMemAlloc(len
* sizeof(WCHAR
));
1668 MultiByteToWideChar(CP_ACP
, 0, pvPara
, -1, str
, len
);
1669 for (ptr
= str
; *ptr
; ptr
++)
1670 *ptr
= tolowerW(*ptr
);
1671 found
= cert_compare_certs_in_store(store
, prev
,
1672 compare_cert_by_name_str
, dwType
, dwFlags
, str
);
1677 found
= find_cert_any(store
, dwType
, dwFlags
, NULL
, prev
);
1681 static PCCERT_CONTEXT
find_cert_by_name_str_w(HCERTSTORE store
, DWORD dwType
,
1682 DWORD dwFlags
, const void *pvPara
, PCCERT_CONTEXT prev
)
1684 PCCERT_CONTEXT found
= NULL
;
1686 TRACE("%s\n", debugstr_w(pvPara
));
1690 DWORD len
= strlenW(pvPara
);
1691 LPWSTR str
= CryptMemAlloc((len
+ 1) * sizeof(WCHAR
));
1698 for (src
= pvPara
, dst
= str
; *src
; src
++, dst
++)
1699 *dst
= tolowerW(*src
);
1701 found
= cert_compare_certs_in_store(store
, prev
,
1702 compare_cert_by_name_str
, dwType
, dwFlags
, str
);
1707 found
= find_cert_any(store
, dwType
, dwFlags
, NULL
, prev
);
1711 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
1712 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
, const void *pvPara
,
1713 PCCERT_CONTEXT pPrevCertContext
)
1716 CertFindFunc find
= NULL
;
1717 CertCompareFunc compare
= NULL
;
1719 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore
, dwCertEncodingType
,
1720 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
1722 switch (dwType
>> CERT_COMPARE_SHIFT
)
1724 case CERT_COMPARE_ANY
:
1725 find
= find_cert_any
;
1727 case CERT_COMPARE_MD5_HASH
:
1728 compare
= compare_cert_by_md5_hash
;
1730 case CERT_COMPARE_SHA1_HASH
:
1731 compare
= compare_cert_by_sha1_hash
;
1733 case CERT_COMPARE_NAME
:
1734 compare
= compare_cert_by_name
;
1736 case CERT_COMPARE_PUBLIC_KEY
:
1737 compare
= compare_cert_by_public_key
;
1739 case CERT_COMPARE_NAME_STR_A
:
1740 find
= find_cert_by_name_str_a
;
1742 case CERT_COMPARE_NAME_STR_W
:
1743 find
= find_cert_by_name_str_w
;
1745 case CERT_COMPARE_SUBJECT_CERT
:
1746 compare
= compare_cert_by_subject_cert
;
1748 case CERT_COMPARE_CERT_ID
:
1749 compare
= compare_cert_by_cert_id
;
1751 case CERT_COMPARE_ISSUER_OF
:
1752 find
= find_cert_by_issuer
;
1754 case CERT_COMPARE_EXISTING
:
1755 compare
= compare_existing_cert
;
1757 case CERT_COMPARE_SIGNATURE_HASH
:
1758 compare
= compare_cert_by_signature_hash
;
1761 FIXME("find type %08x unimplemented\n", dwType
);
1765 ret
= find(hCertStore
, dwFlags
, dwType
, pvPara
, pPrevCertContext
);
1767 ret
= cert_compare_certs_in_store(hCertStore
, pPrevCertContext
,
1768 compare
, dwType
, dwFlags
, pvPara
);
1772 SetLastError(CRYPT_E_NOT_FOUND
);
1773 TRACE("returning %p\n", ret
);
1777 PCCERT_CONTEXT WINAPI
CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore
,
1778 DWORD dwCertEncodingType
, PCERT_INFO pCertId
)
1780 TRACE("(%p, %08x, %p)\n", hCertStore
, dwCertEncodingType
, pCertId
);
1784 SetLastError(E_INVALIDARG
);
1787 return CertFindCertificateInStore(hCertStore
, dwCertEncodingType
, 0,
1788 CERT_FIND_SUBJECT_CERT
, pCertId
, NULL
);
1791 BOOL WINAPI
CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject
,
1792 PCCERT_CONTEXT pIssuer
, DWORD
*pdwFlags
)
1794 static const DWORD supportedFlags
= CERT_STORE_REVOCATION_FLAG
|
1795 CERT_STORE_SIGNATURE_FLAG
| CERT_STORE_TIME_VALIDITY_FLAG
;
1797 if (*pdwFlags
& ~supportedFlags
)
1799 SetLastError(E_INVALIDARG
);
1802 if (*pdwFlags
& CERT_STORE_REVOCATION_FLAG
)
1805 PCCRL_CONTEXT crl
= CertGetCRLFromStore(pSubject
->hCertStore
, pSubject
,
1808 /* FIXME: what if the CRL has expired? */
1811 if (CertVerifyCRLRevocation(pSubject
->dwCertEncodingType
,
1812 pSubject
->pCertInfo
, 1, (PCRL_INFO
*)&crl
->pCrlInfo
))
1813 *pdwFlags
&= CERT_STORE_REVOCATION_FLAG
;
1816 *pdwFlags
|= CERT_STORE_NO_CRL_FLAG
;
1818 if (*pdwFlags
& CERT_STORE_TIME_VALIDITY_FLAG
)
1820 if (0 == CertVerifyTimeValidity(NULL
, pSubject
->pCertInfo
))
1821 *pdwFlags
&= ~CERT_STORE_TIME_VALIDITY_FLAG
;
1823 if (*pdwFlags
& CERT_STORE_SIGNATURE_FLAG
)
1825 if (CryptVerifyCertificateSignatureEx(0, pSubject
->dwCertEncodingType
,
1826 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
, (void *)pSubject
,
1827 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
, (void *)pIssuer
, 0, NULL
))
1828 *pdwFlags
&= ~CERT_STORE_SIGNATURE_FLAG
;
1833 PCCERT_CONTEXT WINAPI
CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore
,
1834 PCCERT_CONTEXT pSubjectContext
, PCCERT_CONTEXT pPrevIssuerContext
,
1839 TRACE("(%p, %p, %p, %08x)\n", hCertStore
, pSubjectContext
,
1840 pPrevIssuerContext
, *pdwFlags
);
1842 if (!pSubjectContext
)
1844 SetLastError(E_INVALIDARG
);
1848 ret
= CertFindCertificateInStore(hCertStore
,
1849 pSubjectContext
->dwCertEncodingType
, 0, CERT_FIND_ISSUER_OF
,
1850 pSubjectContext
, pPrevIssuerContext
);
1853 if (!CertVerifySubjectCertificateContext(pSubjectContext
, ret
,
1856 CertFreeCertificateContext(ret
);
1860 TRACE("returning %p\n", ret
);
1864 typedef struct _OLD_CERT_REVOCATION_STATUS
{
1869 } OLD_CERT_REVOCATION_STATUS
;
1871 typedef BOOL (WINAPI
*CertVerifyRevocationFunc
)(DWORD
, DWORD
, DWORD
,
1872 void **, DWORD
, PCERT_REVOCATION_PARA
, PCERT_REVOCATION_STATUS
);
1874 BOOL WINAPI
CertVerifyRevocation(DWORD dwEncodingType
, DWORD dwRevType
,
1875 DWORD cContext
, PVOID rgpvContext
[], DWORD dwFlags
,
1876 PCERT_REVOCATION_PARA pRevPara
, PCERT_REVOCATION_STATUS pRevStatus
)
1880 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType
, dwRevType
,
1881 cContext
, rgpvContext
, dwFlags
, pRevPara
, pRevStatus
);
1883 if (pRevStatus
->cbSize
!= sizeof(OLD_CERT_REVOCATION_STATUS
) &&
1884 pRevStatus
->cbSize
!= sizeof(CERT_REVOCATION_STATUS
))
1886 SetLastError(E_INVALIDARG
);
1891 static HCRYPTOIDFUNCSET set
= NULL
;
1895 set
= CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC
, 0);
1896 ret
= CryptGetDefaultOIDDllList(set
, dwEncodingType
, NULL
, &size
);
1902 SetLastError(CRYPT_E_NO_REVOCATION_DLL
);
1907 LPWSTR dllList
= CryptMemAlloc(size
* sizeof(WCHAR
)), ptr
;
1911 ret
= CryptGetDefaultOIDDllList(set
, dwEncodingType
,
1915 for (ptr
= dllList
; ret
&& *ptr
;
1916 ptr
+= lstrlenW(ptr
) + 1)
1918 CertVerifyRevocationFunc func
;
1919 HCRYPTOIDFUNCADDR hFunc
;
1921 ret
= CryptGetDefaultOIDFunctionAddress(set
,
1922 dwEncodingType
, ptr
, 0, (void **)&func
, &hFunc
);
1925 ret
= func(dwEncodingType
, dwRevType
, cContext
,
1926 rgpvContext
, dwFlags
, pRevPara
, pRevStatus
);
1927 CryptFreeOIDFunctionAddress(hFunc
, 0);
1931 CryptMemFree(dllList
);
1935 SetLastError(ERROR_OUTOFMEMORY
);
1946 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
1947 CRYPT_ATTRIBUTE rgAttr
[])
1949 PCRYPT_ATTRIBUTE ret
= NULL
;
1952 TRACE("%s %d %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
1958 SetLastError(ERROR_INVALID_PARAMETER
);
1962 for (i
= 0; !ret
&& i
< cAttr
; i
++)
1963 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
1968 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
1969 CERT_EXTENSION rgExtensions
[])
1971 PCERT_EXTENSION ret
= NULL
;
1974 TRACE("%s %d %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
1980 SetLastError(ERROR_INVALID_PARAMETER
);
1984 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
1985 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
1986 rgExtensions
[i
].pszObjId
))
1987 ret
= &rgExtensions
[i
];
1991 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
1993 PCERT_RDN_ATTR ret
= NULL
;
1996 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
2000 SetLastError(ERROR_INVALID_PARAMETER
);
2004 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
2005 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
2006 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
2007 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
2008 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
2012 static BOOL
find_matching_rdn_attr(DWORD dwFlags
, const CERT_NAME_INFO
*name
,
2013 const CERT_RDN_ATTR
*attr
)
2018 for (i
= 0; !match
&& i
< name
->cRDN
; i
++)
2020 for (j
= 0; j
< name
->rgRDN
[i
].cRDNAttr
; j
++)
2022 if (!strcmp(name
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
,
2024 name
->rgRDN
[i
].rgRDNAttr
[j
].dwValueType
==
2027 if (dwFlags
& CERT_UNICODE_IS_RDN_ATTRS_FLAG
)
2030 (LPCWSTR
)name
->rgRDN
[i
].rgRDNAttr
[j
].Value
.pbData
;
2031 LPCWSTR attrStr
= (LPCWSTR
)attr
->Value
.pbData
;
2033 if (attr
->Value
.cbData
!=
2034 name
->rgRDN
[i
].rgRDNAttr
[j
].Value
.cbData
)
2036 else if (dwFlags
& CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG
)
2037 match
= !strncmpiW(nameStr
, attrStr
,
2038 attr
->Value
.cbData
/ sizeof(WCHAR
));
2040 match
= !strncmpW(nameStr
, attrStr
,
2041 attr
->Value
.cbData
/ sizeof(WCHAR
));
2042 TRACE("%s : %s => %d\n",
2043 debugstr_wn(nameStr
, attr
->Value
.cbData
/ sizeof(WCHAR
)),
2044 debugstr_wn(attrStr
, attr
->Value
.cbData
/ sizeof(WCHAR
)),
2050 (LPCSTR
)name
->rgRDN
[i
].rgRDNAttr
[j
].Value
.pbData
;
2051 LPCSTR attrStr
= (LPCSTR
)attr
->Value
.pbData
;
2053 if (attr
->Value
.cbData
!=
2054 name
->rgRDN
[i
].rgRDNAttr
[j
].Value
.cbData
)
2056 else if (dwFlags
& CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG
)
2057 match
= !strncasecmp(nameStr
, attrStr
,
2058 attr
->Value
.cbData
);
2060 match
= !strncmp(nameStr
, attrStr
, attr
->Value
.cbData
);
2061 TRACE("%s : %s => %d\n",
2062 debugstr_an(nameStr
, attr
->Value
.cbData
),
2063 debugstr_an(attrStr
, attr
->Value
.cbData
), match
);
2071 BOOL WINAPI
CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType
,
2072 DWORD dwFlags
, PCERT_NAME_BLOB pCertName
, PCERT_RDN pRDN
)
2074 CERT_NAME_INFO
*name
;
2079 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType
, dwFlags
, pCertName
,
2082 type
= dwFlags
& CERT_UNICODE_IS_RDN_ATTRS_FLAG
? X509_UNICODE_NAME
:
2084 if ((ret
= CryptDecodeObjectEx(dwCertEncodingType
, type
, pCertName
->pbData
,
2085 pCertName
->cbData
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, &name
, &size
)))
2089 for (i
= 0; ret
&& i
< pRDN
->cRDNAttr
; i
++)
2090 ret
= find_matching_rdn_attr(dwFlags
, name
, &pRDN
->rgRDNAttr
[i
]);
2092 SetLastError(CRYPT_E_NO_MATCH
);
2098 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
2099 PCERT_INFO pCertInfo
)
2106 GetSystemTimeAsFileTime(&fileTime
);
2107 pTimeToVerify
= &fileTime
;
2109 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
2111 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
2118 BOOL WINAPI
CertVerifyValidityNesting(PCERT_INFO pSubjectInfo
,
2119 PCERT_INFO pIssuerInfo
)
2121 TRACE("(%p, %p)\n", pSubjectInfo
, pIssuerInfo
);
2123 return CertVerifyTimeValidity(&pSubjectInfo
->NotBefore
, pIssuerInfo
) == 0
2124 && CertVerifyTimeValidity(&pSubjectInfo
->NotAfter
, pIssuerInfo
) == 0;
2127 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv
, ALG_ID Algid
,
2128 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
2129 DWORD
*pcbComputedHash
)
2132 HCRYPTHASH hHash
= 0;
2134 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
2135 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
2138 hCryptProv
= CRYPT_GetDefaultProvider();
2143 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
2146 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
2148 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
2149 pcbComputedHash
, 0);
2150 CryptDestroyHash(hHash
);
2156 BOOL WINAPI
CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv
, ALG_ID Algid
,
2157 DWORD dwFlags
, DWORD dwCertEncodingType
, PCERT_PUBLIC_KEY_INFO pInfo
,
2158 BYTE
*pbComputedHash
, DWORD
*pcbComputedHash
)
2161 HCRYPTHASH hHash
= 0;
2163 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
2164 dwCertEncodingType
, pInfo
, pbComputedHash
, pcbComputedHash
);
2167 hCryptProv
= CRYPT_GetDefaultProvider();
2170 if ((dwCertEncodingType
& CERT_ENCODING_TYPE_MASK
) != X509_ASN_ENCODING
)
2172 SetLastError(ERROR_FILE_NOT_FOUND
);
2180 ret
= CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType
,
2181 X509_PUBLIC_KEY_INFO
, pInfo
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
2182 (LPBYTE
)&buf
, &size
);
2185 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
2188 ret
= CryptHashData(hHash
, buf
, size
, 0);
2190 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
2191 pcbComputedHash
, 0);
2192 CryptDestroyHash(hHash
);
2200 BOOL WINAPI
CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv
,
2201 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
2202 BYTE
*pbComputedHash
, DWORD
*pcbComputedHash
)
2205 CERT_SIGNED_CONTENT_INFO
*info
;
2208 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv
, dwCertEncodingType
,
2209 pbEncoded
, cbEncoded
, pbComputedHash
, *pcbComputedHash
);
2211 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
2212 pbEncoded
, cbEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, &info
, &size
);
2215 PCCRYPT_OID_INFO oidInfo
;
2219 hCryptProv
= CRYPT_GetDefaultProvider();
2220 oidInfo
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2221 info
->SignatureAlgorithm
.pszObjId
, 0);
2224 SetLastError(NTE_BAD_ALGID
);
2229 ret
= CryptCreateHash(hCryptProv
, oidInfo
->u
.Algid
, 0, 0, &hHash
);
2232 ret
= CryptHashData(hHash
, info
->ToBeSigned
.pbData
,
2233 info
->ToBeSigned
.cbData
, 0);
2235 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
2236 pcbComputedHash
, 0);
2237 CryptDestroyHash(hHash
);
2245 BOOL WINAPI
CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv
,
2246 DWORD dwKeySpec
, DWORD dwCertEncodingType
, const BYTE
*pbEncodedToBeSigned
,
2247 DWORD cbEncodedToBeSigned
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
2248 const void *pvHashAuxInfo
, BYTE
*pbSignature
, DWORD
*pcbSignature
)
2251 PCCRYPT_OID_INFO info
;
2254 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv
,
2255 dwKeySpec
, dwCertEncodingType
, pbEncodedToBeSigned
, cbEncodedToBeSigned
,
2256 pSignatureAlgorithm
, pvHashAuxInfo
, pbSignature
, pcbSignature
);
2258 info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2259 pSignatureAlgorithm
->pszObjId
, 0);
2262 SetLastError(NTE_BAD_ALGID
);
2265 if (info
->dwGroupId
== CRYPT_HASH_ALG_OID_GROUP_ID
)
2268 hCryptProv
= CRYPT_GetDefaultProvider();
2269 ret
= CryptCreateHash(hCryptProv
, info
->u
.Algid
, 0, 0, &hHash
);
2272 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
,
2273 cbEncodedToBeSigned
, 0);
2275 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbSignature
,
2277 CryptDestroyHash(hHash
);
2284 SetLastError(ERROR_INVALID_PARAMETER
);
2289 ret
= CryptCreateHash(hCryptProv
, info
->u
.Algid
, 0, 0, &hHash
);
2292 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
,
2293 cbEncodedToBeSigned
, 0);
2295 ret
= CryptSignHashW(hHash
, dwKeySpec
, NULL
, 0, pbSignature
,
2297 CryptDestroyHash(hHash
);
2304 BOOL WINAPI
CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv
,
2305 DWORD dwKeySpec
, DWORD dwCertEncodingType
, LPCSTR lpszStructType
,
2306 const void *pvStructInfo
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
2307 const void *pvHashAuxInfo
, BYTE
*pbEncoded
, DWORD
*pcbEncoded
)
2310 DWORD encodedSize
, hashSize
;
2312 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv
, dwKeySpec
,
2313 dwCertEncodingType
, debugstr_a(lpszStructType
), pvStructInfo
,
2314 pSignatureAlgorithm
, pvHashAuxInfo
, pbEncoded
, pcbEncoded
);
2316 ret
= CryptEncodeObject(dwCertEncodingType
, lpszStructType
, pvStructInfo
,
2317 NULL
, &encodedSize
);
2320 PBYTE encoded
= CryptMemAlloc(encodedSize
);
2324 ret
= CryptEncodeObject(dwCertEncodingType
, lpszStructType
,
2325 pvStructInfo
, encoded
, &encodedSize
);
2328 ret
= CryptSignCertificate(hCryptProv
, dwKeySpec
,
2329 dwCertEncodingType
, encoded
, encodedSize
, pSignatureAlgorithm
,
2330 pvHashAuxInfo
, NULL
, &hashSize
);
2333 PBYTE hash
= CryptMemAlloc(hashSize
);
2337 ret
= CryptSignCertificate(hCryptProv
, dwKeySpec
,
2338 dwCertEncodingType
, encoded
, encodedSize
,
2339 pSignatureAlgorithm
, pvHashAuxInfo
, hash
, &hashSize
);
2342 CERT_SIGNED_CONTENT_INFO info
= { { 0 } };
2344 info
.ToBeSigned
.cbData
= encodedSize
;
2345 info
.ToBeSigned
.pbData
= encoded
;
2346 info
.SignatureAlgorithm
= *pSignatureAlgorithm
;
2347 info
.Signature
.cbData
= hashSize
;
2348 info
.Signature
.pbData
= hash
;
2349 info
.Signature
.cUnusedBits
= 0;
2350 ret
= CryptEncodeObject(dwCertEncodingType
,
2351 X509_CERT
, &info
, pbEncoded
, pcbEncoded
);
2357 CryptMemFree(encoded
);
2363 BOOL WINAPI
CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv
,
2364 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
2365 PCERT_PUBLIC_KEY_INFO pPublicKey
)
2367 CRYPT_DATA_BLOB blob
= { cbEncoded
, (BYTE
*)pbEncoded
};
2369 return CryptVerifyCertificateSignatureEx(hCryptProv
, dwCertEncodingType
,
2370 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
, &blob
,
2371 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
, pPublicKey
, 0, NULL
);
2374 static BOOL
CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv
,
2375 DWORD dwCertEncodingType
, PCERT_PUBLIC_KEY_INFO pubKeyInfo
,
2376 const CERT_SIGNED_CONTENT_INFO
*signedCert
)
2380 PCCRYPT_OID_INFO info
;
2381 ALG_ID pubKeyID
, hashID
;
2383 info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
2384 signedCert
->SignatureAlgorithm
.pszObjId
, 0);
2385 if (!info
|| info
->dwGroupId
!= CRYPT_SIGN_ALG_OID_GROUP_ID
)
2387 SetLastError(NTE_BAD_ALGID
);
2390 hashID
= info
->u
.Algid
;
2391 if (info
->ExtraInfo
.cbData
>= sizeof(ALG_ID
))
2392 pubKeyID
= *(ALG_ID
*)info
->ExtraInfo
.pbData
;
2395 /* Load the default provider if necessary */
2397 hCryptProv
= CRYPT_GetDefaultProvider();
2398 ret
= CryptImportPublicKeyInfoEx(hCryptProv
, dwCertEncodingType
,
2399 pubKeyInfo
, pubKeyID
, 0, NULL
, &key
);
2404 ret
= CryptCreateHash(hCryptProv
, hashID
, 0, 0, &hash
);
2407 ret
= CryptHashData(hash
, signedCert
->ToBeSigned
.pbData
,
2408 signedCert
->ToBeSigned
.cbData
, 0);
2410 ret
= CryptVerifySignatureW(hash
, signedCert
->Signature
.pbData
,
2411 signedCert
->Signature
.cbData
, key
, NULL
, 0);
2412 CryptDestroyHash(hash
);
2414 CryptDestroyKey(key
);
2419 BOOL WINAPI
CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv
,
2420 DWORD dwCertEncodingType
, DWORD dwSubjectType
, void *pvSubject
,
2421 DWORD dwIssuerType
, void *pvIssuer
, DWORD dwFlags
, void *pvReserved
)
2424 CRYPT_DATA_BLOB subjectBlob
;
2426 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv
,
2427 dwCertEncodingType
, dwSubjectType
, pvSubject
, dwIssuerType
, pvIssuer
,
2428 dwFlags
, pvReserved
);
2430 switch (dwSubjectType
)
2432 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
:
2434 PCRYPT_DATA_BLOB blob
= pvSubject
;
2436 subjectBlob
.pbData
= blob
->pbData
;
2437 subjectBlob
.cbData
= blob
->cbData
;
2440 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
:
2442 PCERT_CONTEXT context
= pvSubject
;
2444 subjectBlob
.pbData
= context
->pbCertEncoded
;
2445 subjectBlob
.cbData
= context
->cbCertEncoded
;
2448 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL
:
2450 PCRL_CONTEXT context
= pvSubject
;
2452 subjectBlob
.pbData
= context
->pbCrlEncoded
;
2453 subjectBlob
.cbData
= context
->cbCrlEncoded
;
2457 SetLastError(E_INVALIDARG
);
2463 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
2466 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
2467 subjectBlob
.pbData
, subjectBlob
.cbData
,
2468 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
2469 &signedCert
, &size
);
2472 switch (dwIssuerType
)
2474 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
:
2475 ret
= CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv
,
2476 dwCertEncodingType
, pvIssuer
,
2479 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
:
2480 ret
= CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv
,
2482 &((PCCERT_CONTEXT
)pvIssuer
)->pCertInfo
->SubjectPublicKeyInfo
,
2485 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN
:
2486 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2489 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL
:
2492 SetLastError(E_INVALIDARG
);
2497 FIXME("unimplemented for NULL signer\n");
2498 SetLastError(E_INVALIDARG
);
2503 SetLastError(E_INVALIDARG
);
2506 LocalFree(signedCert
);
2512 BOOL WINAPI
CertGetIntendedKeyUsage(DWORD dwCertEncodingType
,
2513 PCERT_INFO pCertInfo
, BYTE
*pbKeyUsage
, DWORD cbKeyUsage
)
2515 PCERT_EXTENSION ext
;
2518 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType
, pCertInfo
, pbKeyUsage
,
2521 ext
= CertFindExtension(szOID_KEY_USAGE
, pCertInfo
->cExtension
,
2522 pCertInfo
->rgExtension
);
2525 CRYPT_BIT_BLOB usage
;
2526 DWORD size
= sizeof(usage
);
2528 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_BITS
,
2529 ext
->Value
.pbData
, ext
->Value
.cbData
, CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
2533 if (cbKeyUsage
< usage
.cbData
)
2537 memcpy(pbKeyUsage
, usage
.pbData
, usage
.cbData
);
2538 if (cbKeyUsage
> usage
.cbData
)
2539 memset(pbKeyUsage
+ usage
.cbData
, 0,
2540 cbKeyUsage
- usage
.cbData
);
2549 BOOL WINAPI
CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext
, DWORD dwFlags
,
2550 PCERT_ENHKEY_USAGE pUsage
, DWORD
*pcbUsage
)
2552 PCERT_ENHKEY_USAGE usage
= NULL
;
2556 if (!pCertContext
|| !pcbUsage
)
2558 SetLastError(ERROR_INVALID_PARAMETER
);
2562 TRACE("(%p, %08x, %p, %d)\n", pCertContext
, dwFlags
, pUsage
, *pcbUsage
);
2564 if (!(dwFlags
& CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
))
2568 if (CertGetCertificateContextProperty(pCertContext
,
2569 CERT_ENHKEY_USAGE_PROP_ID
, NULL
, &propSize
))
2571 LPBYTE buf
= CryptMemAlloc(propSize
);
2575 if (CertGetCertificateContextProperty(pCertContext
,
2576 CERT_ENHKEY_USAGE_PROP_ID
, buf
, &propSize
))
2578 ret
= CryptDecodeObjectEx(pCertContext
->dwCertEncodingType
,
2579 X509_ENHANCED_KEY_USAGE
, buf
, propSize
,
2580 CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &usage
, &bytesNeeded
);
2586 if (!usage
&& !(dwFlags
& CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
))
2588 PCERT_EXTENSION ext
= CertFindExtension(szOID_ENHANCED_KEY_USAGE
,
2589 pCertContext
->pCertInfo
->cExtension
,
2590 pCertContext
->pCertInfo
->rgExtension
);
2594 ret
= CryptDecodeObjectEx(pCertContext
->dwCertEncodingType
,
2595 X509_ENHANCED_KEY_USAGE
, ext
->Value
.pbData
, ext
->Value
.cbData
,
2596 CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &usage
, &bytesNeeded
);
2601 /* If a particular location is specified, this should fail. Otherwise
2602 * it should succeed with an empty usage. (This is true on Win2k and
2603 * later, which we emulate.)
2607 SetLastError(CRYPT_E_NOT_FOUND
);
2611 bytesNeeded
= sizeof(CERT_ENHKEY_USAGE
);
2617 *pcbUsage
= bytesNeeded
;
2618 else if (*pcbUsage
< bytesNeeded
)
2620 SetLastError(ERROR_MORE_DATA
);
2621 *pcbUsage
= bytesNeeded
;
2626 *pcbUsage
= bytesNeeded
;
2630 LPSTR nextOID
= (LPSTR
)((LPBYTE
)pUsage
+
2631 sizeof(CERT_ENHKEY_USAGE
) +
2632 usage
->cUsageIdentifier
* sizeof(LPSTR
));
2634 pUsage
->cUsageIdentifier
= usage
->cUsageIdentifier
;
2635 pUsage
->rgpszUsageIdentifier
= (LPSTR
*)((LPBYTE
)pUsage
+
2636 sizeof(CERT_ENHKEY_USAGE
));
2637 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
2639 pUsage
->rgpszUsageIdentifier
[i
] = nextOID
;
2640 strcpy(nextOID
, usage
->rgpszUsageIdentifier
[i
]);
2641 nextOID
+= strlen(nextOID
) + 1;
2645 pUsage
->cUsageIdentifier
= 0;
2650 TRACE("returning %d\n", ret
);
2654 BOOL WINAPI
CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext
,
2655 PCERT_ENHKEY_USAGE pUsage
)
2659 TRACE("(%p, %p)\n", pCertContext
, pUsage
);
2663 CRYPT_DATA_BLOB blob
= { 0, NULL
};
2665 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_ENHANCED_KEY_USAGE
,
2666 pUsage
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &blob
.pbData
, &blob
.cbData
);
2669 ret
= CertSetCertificateContextProperty(pCertContext
,
2670 CERT_ENHKEY_USAGE_PROP_ID
, 0, &blob
);
2671 LocalFree(blob
.pbData
);
2675 ret
= CertSetCertificateContextProperty(pCertContext
,
2676 CERT_ENHKEY_USAGE_PROP_ID
, 0, NULL
);
2680 BOOL WINAPI
CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext
,
2681 LPCSTR pszUsageIdentifier
)
2686 TRACE("(%p, %s)\n", pCertContext
, debugstr_a(pszUsageIdentifier
));
2688 if (CertGetEnhancedKeyUsage(pCertContext
,
2689 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, NULL
, &size
))
2691 PCERT_ENHKEY_USAGE usage
= CryptMemAlloc(size
);
2695 ret
= CertGetEnhancedKeyUsage(pCertContext
,
2696 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
);
2700 BOOL exists
= FALSE
;
2702 /* Make sure usage doesn't already exist */
2703 for (i
= 0; !exists
&& i
< usage
->cUsageIdentifier
; i
++)
2705 if (!strcmp(usage
->rgpszUsageIdentifier
[i
],
2706 pszUsageIdentifier
))
2711 PCERT_ENHKEY_USAGE newUsage
= CryptMemAlloc(size
+
2712 sizeof(LPSTR
) + strlen(pszUsageIdentifier
) + 1);
2718 newUsage
->rgpszUsageIdentifier
= (LPSTR
*)
2719 ((LPBYTE
)newUsage
+ sizeof(CERT_ENHKEY_USAGE
));
2720 nextOID
= (LPSTR
)((LPBYTE
)newUsage
->rgpszUsageIdentifier
2721 + (usage
->cUsageIdentifier
+ 1) * sizeof(LPSTR
));
2722 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
2724 newUsage
->rgpszUsageIdentifier
[i
] = nextOID
;
2725 strcpy(nextOID
, usage
->rgpszUsageIdentifier
[i
]);
2726 nextOID
+= strlen(nextOID
) + 1;
2728 newUsage
->rgpszUsageIdentifier
[i
] = nextOID
;
2729 strcpy(nextOID
, pszUsageIdentifier
);
2730 newUsage
->cUsageIdentifier
= i
+ 1;
2731 ret
= CertSetEnhancedKeyUsage(pCertContext
, newUsage
);
2732 CryptMemFree(newUsage
);
2738 CryptMemFree(usage
);
2745 PCERT_ENHKEY_USAGE usage
= CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE
) +
2746 sizeof(LPSTR
) + strlen(pszUsageIdentifier
) + 1);
2750 usage
->rgpszUsageIdentifier
=
2751 (LPSTR
*)((LPBYTE
)usage
+ sizeof(CERT_ENHKEY_USAGE
));
2752 usage
->rgpszUsageIdentifier
[0] = (LPSTR
)((LPBYTE
)usage
+
2753 sizeof(CERT_ENHKEY_USAGE
) + sizeof(LPSTR
));
2754 strcpy(usage
->rgpszUsageIdentifier
[0], pszUsageIdentifier
);
2755 usage
->cUsageIdentifier
= 1;
2756 ret
= CertSetEnhancedKeyUsage(pCertContext
, usage
);
2757 CryptMemFree(usage
);
2765 BOOL WINAPI
CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext
,
2766 LPCSTR pszUsageIdentifier
)
2770 CERT_ENHKEY_USAGE usage
;
2772 TRACE("(%p, %s)\n", pCertContext
, debugstr_a(pszUsageIdentifier
));
2774 size
= sizeof(usage
);
2775 ret
= CertGetEnhancedKeyUsage(pCertContext
,
2776 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, &usage
, &size
);
2777 if (!ret
&& GetLastError() == ERROR_MORE_DATA
)
2779 PCERT_ENHKEY_USAGE pUsage
= CryptMemAlloc(size
);
2783 ret
= CertGetEnhancedKeyUsage(pCertContext
,
2784 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, pUsage
, &size
);
2787 if (pUsage
->cUsageIdentifier
)
2792 for (i
= 0; i
< pUsage
->cUsageIdentifier
; i
++)
2794 if (!strcmp(pUsage
->rgpszUsageIdentifier
[i
],
2795 pszUsageIdentifier
))
2797 if (found
&& i
< pUsage
->cUsageIdentifier
- 1)
2798 pUsage
->rgpszUsageIdentifier
[i
] =
2799 pUsage
->rgpszUsageIdentifier
[i
+ 1];
2801 pUsage
->cUsageIdentifier
--;
2802 /* Remove the usage if it's empty */
2803 if (pUsage
->cUsageIdentifier
)
2804 ret
= CertSetEnhancedKeyUsage(pCertContext
, pUsage
);
2806 ret
= CertSetEnhancedKeyUsage(pCertContext
, NULL
);
2809 CryptMemFree(pUsage
);
2816 /* it fit in an empty usage, therefore there's nothing to remove */
2828 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2830 static void CRYPT_SetBitInField(struct BitField
*field
, DWORD bit
)
2832 DWORD indexIndex
= bit
/ BITS_PER_DWORD
;
2834 if (indexIndex
+ 1 > field
->cIndexes
)
2836 if (field
->cIndexes
)
2837 field
->indexes
= CryptMemRealloc(field
->indexes
,
2838 (indexIndex
+ 1) * sizeof(DWORD
));
2840 field
->indexes
= CryptMemAlloc(sizeof(DWORD
));
2843 field
->indexes
[indexIndex
] = 0;
2844 field
->cIndexes
= indexIndex
+ 1;
2848 field
->indexes
[indexIndex
] |= 1 << (bit
% BITS_PER_DWORD
);
2851 static BOOL
CRYPT_IsBitInFieldSet(const struct BitField
*field
, DWORD bit
)
2854 DWORD indexIndex
= bit
/ BITS_PER_DWORD
;
2856 assert(field
->cIndexes
);
2857 set
= field
->indexes
[indexIndex
] & (1 << (bit
% BITS_PER_DWORD
));
2861 BOOL WINAPI
CertGetValidUsages(DWORD cCerts
, PCCERT_CONTEXT
*rghCerts
,
2862 int *cNumOIDs
, LPSTR
*rghOIDs
, DWORD
*pcbOIDs
)
2865 DWORD i
, cbOIDs
= 0;
2866 BOOL allUsagesValid
= TRUE
;
2867 CERT_ENHKEY_USAGE validUsages
= { 0, NULL
};
2869 TRACE("(%d, %p, %d, %p, %d)\n", cCerts
, rghCerts
, *cNumOIDs
,
2872 for (i
= 0; i
< cCerts
; i
++)
2874 CERT_ENHKEY_USAGE usage
;
2875 DWORD size
= sizeof(usage
);
2877 ret
= CertGetEnhancedKeyUsage(rghCerts
[i
], 0, &usage
, &size
);
2878 /* Success is deliberately ignored: it implies all usages are valid */
2879 if (!ret
&& GetLastError() == ERROR_MORE_DATA
)
2881 PCERT_ENHKEY_USAGE pUsage
= CryptMemAlloc(size
);
2883 allUsagesValid
= FALSE
;
2886 ret
= CertGetEnhancedKeyUsage(rghCerts
[i
], 0, pUsage
, &size
);
2889 if (!validUsages
.cUsageIdentifier
)
2893 cbOIDs
= pUsage
->cUsageIdentifier
* sizeof(LPSTR
);
2894 validUsages
.cUsageIdentifier
= pUsage
->cUsageIdentifier
;
2895 for (j
= 0; j
< validUsages
.cUsageIdentifier
; j
++)
2896 cbOIDs
+= lstrlenA(pUsage
->rgpszUsageIdentifier
[j
])
2898 validUsages
.rgpszUsageIdentifier
=
2899 CryptMemAlloc(cbOIDs
);
2900 if (validUsages
.rgpszUsageIdentifier
)
2902 LPSTR nextOID
= (LPSTR
)
2903 ((LPBYTE
)validUsages
.rgpszUsageIdentifier
+
2904 validUsages
.cUsageIdentifier
* sizeof(LPSTR
));
2906 for (j
= 0; j
< validUsages
.cUsageIdentifier
; j
++)
2908 validUsages
.rgpszUsageIdentifier
[j
] = nextOID
;
2909 lstrcpyA(validUsages
.rgpszUsageIdentifier
[j
],
2910 pUsage
->rgpszUsageIdentifier
[j
]);
2911 nextOID
+= lstrlenA(nextOID
) + 1;
2917 struct BitField validIndexes
= { 0, NULL
};
2918 DWORD j
, k
, numRemoved
= 0;
2920 /* Merge: build a bitmap of all the indexes of
2921 * validUsages.rgpszUsageIdentifier that are in pUsage.
2923 for (j
= 0; j
< pUsage
->cUsageIdentifier
; j
++)
2925 for (k
= 0; k
< validUsages
.cUsageIdentifier
; k
++)
2927 if (!strcmp(pUsage
->rgpszUsageIdentifier
[j
],
2928 validUsages
.rgpszUsageIdentifier
[k
]))
2930 CRYPT_SetBitInField(&validIndexes
, k
);
2935 /* Merge by removing from validUsages those that are
2936 * not in the bitmap.
2938 for (j
= 0; j
< validUsages
.cUsageIdentifier
; j
++)
2940 if (!CRYPT_IsBitInFieldSet(&validIndexes
, j
))
2942 if (j
< validUsages
.cUsageIdentifier
- 1)
2944 memmove(&validUsages
.rgpszUsageIdentifier
[j
],
2945 &validUsages
.rgpszUsageIdentifier
[j
+
2947 (validUsages
.cUsageIdentifier
- numRemoved
2948 - j
- 1) * sizeof(LPSTR
));
2950 validUsages
.rgpszUsageIdentifier
[j
]) + 1 +
2952 validUsages
.cUsageIdentifier
--;
2956 validUsages
.cUsageIdentifier
--;
2959 CryptMemFree(validIndexes
.indexes
);
2962 CryptMemFree(pUsage
);
2974 *cNumOIDs
= validUsages
.cUsageIdentifier
;
2977 else if (*pcbOIDs
< cbOIDs
)
2980 SetLastError(ERROR_MORE_DATA
);
2985 LPSTR nextOID
= (LPSTR
)((LPBYTE
)rghOIDs
+
2986 validUsages
.cUsageIdentifier
* sizeof(LPSTR
));
2989 for (i
= 0; i
< validUsages
.cUsageIdentifier
; i
++)
2991 rghOIDs
[i
] = nextOID
;
2992 lstrcpyA(nextOID
, validUsages
.rgpszUsageIdentifier
[i
]);
2993 nextOID
+= lstrlenA(nextOID
) + 1;
2997 CryptMemFree(validUsages
.rgpszUsageIdentifier
);
2998 TRACE("cNumOIDs: %d\n", *cNumOIDs
);
2999 TRACE("returning %d\n", ret
);
3003 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
3004 * pInfo is NULL, from the attributes of hProv.
3006 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context
,
3007 const CRYPT_KEY_PROV_INFO
*pInfo
, HCRYPTPROV hProv
)
3009 CRYPT_KEY_PROV_INFO info
= { 0 };
3017 ret
= CryptGetProvParam(hProv
, PP_CONTAINER
, NULL
, &size
, 0);
3020 LPSTR szContainer
= CryptMemAlloc(size
);
3024 ret
= CryptGetProvParam(hProv
, PP_CONTAINER
,
3025 (BYTE
*)szContainer
, &size
, 0);
3028 len
= MultiByteToWideChar(CP_ACP
, 0, szContainer
, -1,
3032 info
.pwszContainerName
= CryptMemAlloc(len
*
3034 MultiByteToWideChar(CP_ACP
, 0, szContainer
, -1,
3035 info
.pwszContainerName
, len
);
3038 CryptMemFree(szContainer
);
3041 ret
= CryptGetProvParam(hProv
, PP_NAME
, NULL
, &size
, 0);
3044 LPSTR szProvider
= CryptMemAlloc(size
);
3048 ret
= CryptGetProvParam(hProv
, PP_NAME
, (BYTE
*)szProvider
,
3052 len
= MultiByteToWideChar(CP_ACP
, 0, szProvider
, -1,
3056 info
.pwszProvName
= CryptMemAlloc(len
*
3058 MultiByteToWideChar(CP_ACP
, 0, szProvider
, -1,
3059 info
.pwszProvName
, len
);
3062 CryptMemFree(szProvider
);
3065 size
= sizeof(info
.dwKeySpec
);
3066 /* in case no CRYPT_KEY_PROV_INFO given,
3067 * we always use AT_SIGNATURE key spec
3069 info
.dwKeySpec
= AT_SIGNATURE
;
3070 size
= sizeof(info
.dwProvType
);
3071 ret
= CryptGetProvParam(hProv
, PP_PROVTYPE
, (LPBYTE
)&info
.dwProvType
,
3074 info
.dwProvType
= PROV_RSA_FULL
;
3078 CertSetCertificateContextProperty(context
, CERT_KEY_PROV_INFO_PROP_ID
,
3083 CryptMemFree(info
.pwszContainerName
);
3084 CryptMemFree(info
.pwszProvName
);
3088 /* Creates a signed certificate context from the unsigned, encoded certificate
3089 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
3091 static PCCERT_CONTEXT
CRYPT_CreateSignedCert(const CRYPT_DER_BLOB
*blob
,
3092 HCRYPTPROV hProv
, DWORD dwKeySpec
, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo
)
3094 PCCERT_CONTEXT context
= NULL
;
3098 ret
= CryptSignCertificate(hProv
, dwKeySpec
, X509_ASN_ENCODING
,
3099 blob
->pbData
, blob
->cbData
, sigAlgo
, NULL
, NULL
, &sigSize
);
3102 LPBYTE sig
= CryptMemAlloc(sigSize
);
3104 ret
= CryptSignCertificate(hProv
, dwKeySpec
, X509_ASN_ENCODING
,
3105 blob
->pbData
, blob
->cbData
, sigAlgo
, NULL
, sig
, &sigSize
);
3108 CERT_SIGNED_CONTENT_INFO signedInfo
;
3109 BYTE
*encodedSignedCert
= NULL
;
3110 DWORD encodedSignedCertSize
= 0;
3112 signedInfo
.ToBeSigned
.cbData
= blob
->cbData
;
3113 signedInfo
.ToBeSigned
.pbData
= blob
->pbData
;
3114 signedInfo
.SignatureAlgorithm
= *sigAlgo
;
3115 signedInfo
.Signature
.cbData
= sigSize
;
3116 signedInfo
.Signature
.pbData
= sig
;
3117 signedInfo
.Signature
.cUnusedBits
= 0;
3118 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_CERT
,
3119 &signedInfo
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
3120 &encodedSignedCert
, &encodedSignedCertSize
);
3123 context
= CertCreateCertificateContext(X509_ASN_ENCODING
,
3124 encodedSignedCert
, encodedSignedCertSize
);
3125 LocalFree(encodedSignedCert
);
3133 /* Copies data from the parameters into info, where:
3134 * pSerialNumber: The serial number. Must not be NULL.
3135 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3137 * pSignatureAlgorithm: Optional.
3138 * pStartTime: The starting time of the certificate. If NULL, the current
3139 * system time is used.
3140 * pEndTime: The ending time of the certificate. If NULL, one year past the
3141 * starting time is used.
3142 * pubKey: The public key of the certificate. Must not be NULL.
3143 * pExtensions: Extensions to be included with the certificate. Optional.
3145 static void CRYPT_MakeCertInfo(PCERT_INFO info
, const CRYPT_DATA_BLOB
*pSerialNumber
,
3146 const CERT_NAME_BLOB
*pSubjectIssuerBlob
,
3147 const CRYPT_ALGORITHM_IDENTIFIER
*pSignatureAlgorithm
, const SYSTEMTIME
*pStartTime
,
3148 const SYSTEMTIME
*pEndTime
, const CERT_PUBLIC_KEY_INFO
*pubKey
,
3149 const CERT_EXTENSIONS
*pExtensions
)
3151 static CHAR oid
[] = szOID_RSA_SHA1RSA
;
3154 assert(pSerialNumber
);
3155 assert(pSubjectIssuerBlob
);
3158 if (pExtensions
&& pExtensions
->cExtension
)
3159 info
->dwVersion
= CERT_V3
;
3161 info
->dwVersion
= CERT_V1
;
3162 info
->SerialNumber
.cbData
= pSerialNumber
->cbData
;
3163 info
->SerialNumber
.pbData
= pSerialNumber
->pbData
;
3164 if (pSignatureAlgorithm
)
3165 info
->SignatureAlgorithm
= *pSignatureAlgorithm
;
3168 info
->SignatureAlgorithm
.pszObjId
= oid
;
3169 info
->SignatureAlgorithm
.Parameters
.cbData
= 0;
3170 info
->SignatureAlgorithm
.Parameters
.pbData
= NULL
;
3172 info
->Issuer
.cbData
= pSubjectIssuerBlob
->cbData
;
3173 info
->Issuer
.pbData
= pSubjectIssuerBlob
->pbData
;
3175 SystemTimeToFileTime(pStartTime
, &info
->NotBefore
);
3177 GetSystemTimeAsFileTime(&info
->NotBefore
);
3179 SystemTimeToFileTime(pEndTime
, &info
->NotAfter
);
3184 if (FileTimeToSystemTime(&info
->NotBefore
, &endTime
))
3187 SystemTimeToFileTime(&endTime
, &info
->NotAfter
);
3190 info
->Subject
.cbData
= pSubjectIssuerBlob
->cbData
;
3191 info
->Subject
.pbData
= pSubjectIssuerBlob
->pbData
;
3192 info
->SubjectPublicKeyInfo
= *pubKey
;
3195 info
->cExtension
= pExtensions
->cExtension
;
3196 info
->rgExtension
= pExtensions
->rgExtension
;
3200 info
->cExtension
= 0;
3201 info
->rgExtension
= NULL
;
3205 typedef RPC_STATUS (RPC_ENTRY
*UuidCreateFunc
)(UUID
*);
3206 typedef RPC_STATUS (RPC_ENTRY
*UuidToStringFunc
)(UUID
*, unsigned char **);
3207 typedef RPC_STATUS (RPC_ENTRY
*RpcStringFreeFunc
)(unsigned char **);
3209 static HCRYPTPROV
CRYPT_CreateKeyProv(void)
3211 HCRYPTPROV hProv
= 0;
3212 HMODULE rpcrt
= LoadLibraryA("rpcrt4");
3216 UuidCreateFunc uuidCreate
= (UuidCreateFunc
)GetProcAddress(rpcrt
,
3218 UuidToStringFunc uuidToString
= (UuidToStringFunc
)GetProcAddress(rpcrt
,
3220 RpcStringFreeFunc rpcStringFree
= (RpcStringFreeFunc
)GetProcAddress(
3221 rpcrt
, "RpcStringFreeA");
3223 if (uuidCreate
&& uuidToString
&& rpcStringFree
)
3226 RPC_STATUS status
= uuidCreate(&uuid
);
3228 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
)
3230 unsigned char *uuidStr
;
3232 status
= uuidToString(&uuid
, &uuidStr
);
3233 if (status
== RPC_S_OK
)
3235 BOOL ret
= CryptAcquireContextA(&hProv
, (LPCSTR
)uuidStr
,
3236 MS_DEF_PROV_A
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
);
3242 ret
= CryptGenKey(hProv
, AT_SIGNATURE
, 0, &key
);
3244 CryptDestroyKey(key
);
3246 rpcStringFree(&uuidStr
);
3255 PCCERT_CONTEXT WINAPI
CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv
,
3256 PCERT_NAME_BLOB pSubjectIssuerBlob
, DWORD dwFlags
,
3257 PCRYPT_KEY_PROV_INFO pKeyProvInfo
,
3258 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
, PSYSTEMTIME pStartTime
,
3259 PSYSTEMTIME pEndTime
, PCERT_EXTENSIONS pExtensions
)
3261 PCCERT_CONTEXT context
= NULL
;
3262 BOOL ret
, releaseContext
= FALSE
;
3263 PCERT_PUBLIC_KEY_INFO pubKey
= NULL
;
3264 DWORD pubKeySize
= 0, dwKeySpec
;
3266 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv
,
3267 pSubjectIssuerBlob
, dwFlags
, pKeyProvInfo
, pSignatureAlgorithm
, pStartTime
,
3268 pExtensions
, pExtensions
);
3270 if(!pSubjectIssuerBlob
)
3272 SetLastError(ERROR_INVALID_PARAMETER
);
3276 dwKeySpec
= pKeyProvInfo
? pKeyProvInfo
->dwKeySpec
: AT_SIGNATURE
;
3281 hProv
= CRYPT_CreateKeyProv();
3282 releaseContext
= TRUE
;
3284 else if (pKeyProvInfo
->dwFlags
& CERT_SET_KEY_PROV_HANDLE_PROP_ID
)
3286 SetLastError(NTE_BAD_FLAGS
);
3292 /* acquire the context using the given information*/
3293 ret
= CryptAcquireContextW(&hProv
,pKeyProvInfo
->pwszContainerName
,
3294 pKeyProvInfo
->pwszProvName
,pKeyProvInfo
->dwProvType
,
3295 pKeyProvInfo
->dwFlags
);
3298 if(GetLastError() != NTE_BAD_KEYSET
)
3300 /* create the key set */
3301 ret
= CryptAcquireContextW(&hProv
,pKeyProvInfo
->pwszContainerName
,
3302 pKeyProvInfo
->pwszProvName
,pKeyProvInfo
->dwProvType
,
3303 pKeyProvInfo
->dwFlags
|CRYPT_NEWKEYSET
);
3307 /* check if the key is here */
3308 ret
= CryptGetUserKey(hProv
,dwKeySpec
,&hKey
);
3311 if (NTE_NO_KEY
== GetLastError())
3312 { /* generate the key */
3313 ret
= CryptGenKey(hProv
,dwKeySpec
,0,&hKey
);
3317 CryptReleaseContext(hProv
,0);
3318 SetLastError(NTE_BAD_KEYSET
);
3322 CryptDestroyKey(hKey
);
3323 releaseContext
= TRUE
;
3327 ret
= CryptExportPublicKeyInfo(hProv
, dwKeySpec
, X509_ASN_ENCODING
, NULL
,
3331 pubKey
= CryptMemAlloc(pubKeySize
);
3334 ret
= CryptExportPublicKeyInfo(hProv
, dwKeySpec
, X509_ASN_ENCODING
,
3335 pubKey
, &pubKeySize
);
3338 CERT_INFO info
= { 0 };
3339 CRYPT_DER_BLOB blob
= { 0, NULL
};
3341 CRYPT_DATA_BLOB serialBlob
= { sizeof(serial
), serial
};
3343 CryptGenRandom(hProv
, sizeof(serial
), serial
);
3344 CRYPT_MakeCertInfo(&info
, &serialBlob
, pSubjectIssuerBlob
,
3345 pSignatureAlgorithm
, pStartTime
, pEndTime
, pubKey
, pExtensions
);
3346 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
3347 &info
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &blob
.pbData
,
3351 if (!(dwFlags
& CERT_CREATE_SELFSIGN_NO_SIGN
))
3352 context
= CRYPT_CreateSignedCert(&blob
, hProv
,dwKeySpec
,
3353 &info
.SignatureAlgorithm
);
3355 context
= CertCreateCertificateContext(X509_ASN_ENCODING
,
3356 blob
.pbData
, blob
.cbData
);
3357 if (context
&& !(dwFlags
& CERT_CREATE_SELFSIGN_NO_KEY_INFO
))
3358 CertContext_SetKeyProvInfo(context
, pKeyProvInfo
, hProv
);
3359 LocalFree(blob
.pbData
);
3362 CryptMemFree(pubKey
);
3366 CryptReleaseContext(hProv
, 0);
3370 BOOL WINAPI
CertVerifyCTLUsage(DWORD dwEncodingType
, DWORD dwSubjectType
,
3371 void *pvSubject
, PCTL_USAGE pSubjectUsage
, DWORD dwFlags
,
3372 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara
,
3373 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus
)
3375 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType
,
3376 dwSubjectType
, pvSubject
, pSubjectUsage
, dwFlags
, pVerifyUsagePara
,
3377 pVerifyUsageStatus
);
3378 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
3382 const void * WINAPI
CertCreateContext(DWORD dwContextType
, DWORD dwEncodingType
,
3383 const BYTE
*pbEncoded
, DWORD cbEncoded
,
3384 DWORD dwFlags
, PCERT_CREATE_CONTEXT_PARA pCreatePara
)
3386 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType
, dwEncodingType
,
3387 pbEncoded
, cbEncoded
, dwFlags
, pCreatePara
);
3391 FIXME("dwFlags 0x%08x not handled\n", dwFlags
);
3396 FIXME("pCreatePara not handled\n");
3400 switch (dwContextType
)
3402 case CERT_STORE_CERTIFICATE_CONTEXT
:
3403 return CertCreateCertificateContext(dwEncodingType
, pbEncoded
, cbEncoded
);
3404 case CERT_STORE_CRL_CONTEXT
:
3405 return CertCreateCRLContext(dwEncodingType
, pbEncoded
, cbEncoded
);
3406 case CERT_STORE_CTL_CONTEXT
:
3407 return CertCreateCTLContext(dwEncodingType
, pbEncoded
, cbEncoded
);
3409 WARN("unknown context type: 0x%x\n", dwContextType
);