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
27 #include "wine/debug.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
32 /* Internal version of CertGetCertificateContextProperty that gets properties
33 * directly from the context (or the context it's linked to, depending on its
34 * type.) Doesn't handle special-case properties, since they are handled by
35 * CertGetCertificateContextProperty, and are particular to the store in which
36 * the property exists (which is separate from the context.)
38 static BOOL WINAPI
CertContext_GetProperty(void *context
, DWORD dwPropId
,
39 void *pvData
, DWORD
*pcbData
);
41 /* Internal version of CertSetCertificateContextProperty that sets properties
42 * directly on the context (or the context it's linked to, depending on its
43 * type.) Doesn't handle special cases, since they're handled by
44 * CertSetCertificateContextProperty anyway.
46 static BOOL WINAPI
CertContext_SetProperty(void *context
, DWORD dwPropId
,
47 DWORD dwFlags
, const void *pvData
);
49 BOOL WINAPI
CertAddEncodedCertificateToStore(HCERTSTORE hCertStore
,
50 DWORD dwCertEncodingType
, const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
,
51 DWORD dwAddDisposition
, PCCERT_CONTEXT
*ppCertContext
)
53 PCCERT_CONTEXT cert
= CertCreateCertificateContext(dwCertEncodingType
,
54 pbCertEncoded
, cbCertEncoded
);
57 TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore
, dwCertEncodingType
,
58 pbCertEncoded
, cbCertEncoded
, dwAddDisposition
, ppCertContext
);
62 ret
= CertAddCertificateContextToStore(hCertStore
, cert
,
63 dwAddDisposition
, ppCertContext
);
64 CertFreeCertificateContext(cert
);
71 PCCERT_CONTEXT WINAPI
CertCreateCertificateContext(DWORD dwCertEncodingType
,
72 const BYTE
*pbCertEncoded
, DWORD cbCertEncoded
)
74 PCERT_CONTEXT cert
= NULL
;
76 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
77 PCERT_INFO certInfo
= NULL
;
80 TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType
, pbCertEncoded
,
83 /* First try to decode it as a signed cert. */
84 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
, pbCertEncoded
,
85 cbCertEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, (BYTE
*)&signedCert
, &size
);
89 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
,
90 signedCert
->ToBeSigned
.pbData
, signedCert
->ToBeSigned
.cbData
,
91 CRYPT_DECODE_ALLOC_FLAG
, NULL
, (BYTE
*)&certInfo
, &size
);
92 LocalFree(signedCert
);
94 /* Failing that, try it as an unsigned cert */
98 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT_TO_BE_SIGNED
,
99 pbCertEncoded
, cbCertEncoded
,
100 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
101 (BYTE
*)&certInfo
, &size
);
107 cert
= (PCERT_CONTEXT
)Context_CreateDataContext(sizeof(CERT_CONTEXT
));
110 data
= CryptMemAlloc(cbCertEncoded
);
117 memcpy(data
, pbCertEncoded
, cbCertEncoded
);
118 cert
->dwCertEncodingType
= dwCertEncodingType
;
119 cert
->pbCertEncoded
= data
;
120 cert
->cbCertEncoded
= cbCertEncoded
;
121 cert
->pCertInfo
= certInfo
;
122 cert
->hCertStore
= 0;
126 return (PCCERT_CONTEXT
)cert
;
129 PCCERT_CONTEXT WINAPI
CertDuplicateCertificateContext(
130 PCCERT_CONTEXT pCertContext
)
132 TRACE("(%p)\n", pCertContext
);
133 Context_AddRef((void *)pCertContext
, sizeof(CERT_CONTEXT
));
137 static void CertDataContext_Free(void *context
)
139 PCERT_CONTEXT certContext
= (PCERT_CONTEXT
)context
;
141 CryptMemFree(certContext
->pbCertEncoded
);
142 LocalFree(certContext
->pCertInfo
);
145 BOOL WINAPI
CertFreeCertificateContext(PCCERT_CONTEXT pCertContext
)
147 TRACE("(%p)\n", pCertContext
);
150 Context_Release((void *)pCertContext
, sizeof(CERT_CONTEXT
),
151 CertDataContext_Free
);
155 DWORD WINAPI
CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext
,
158 PCONTEXT_PROPERTY_LIST properties
= Context_GetProperties(
159 (void *)pCertContext
, sizeof(CERT_CONTEXT
));
162 TRACE("(%p, %ld)\n", pCertContext
, dwPropId
);
165 ret
= ContextPropertyList_EnumPropIDs(properties
, dwPropId
);
171 static BOOL
CertContext_GetHashProp(void *context
, DWORD dwPropId
,
172 ALG_ID algID
, const BYTE
*toHash
, DWORD toHashLen
, void *pvData
,
175 BOOL ret
= CryptHashCertificate(0, algID
, 0, toHash
, toHashLen
, pvData
,
179 CRYPT_DATA_BLOB blob
= { *pcbData
, pvData
};
181 ret
= CertContext_SetProperty(context
, dwPropId
, 0, &blob
);
186 static BOOL WINAPI
CertContext_GetProperty(void *context
, DWORD dwPropId
,
187 void *pvData
, DWORD
*pcbData
)
189 PCCERT_CONTEXT pCertContext
= (PCCERT_CONTEXT
)context
;
190 PCONTEXT_PROPERTY_LIST properties
=
191 Context_GetProperties(context
, sizeof(CERT_CONTEXT
));
193 CRYPT_DATA_BLOB blob
;
195 TRACE("(%p, %ld, %p, %p)\n", context
, dwPropId
, pvData
, pcbData
);
198 ret
= ContextPropertyList_FindProperty(properties
, dwPropId
, &blob
);
205 *pcbData
= blob
.cbData
;
208 else if (*pcbData
< blob
.cbData
)
210 SetLastError(ERROR_MORE_DATA
);
211 *pcbData
= blob
.cbData
;
215 memcpy(pvData
, blob
.pbData
, blob
.cbData
);
216 *pcbData
= blob
.cbData
;
222 /* Implicit properties */
225 case CERT_SHA1_HASH_PROP_ID
:
226 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_SHA1
,
227 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
, pvData
,
230 case CERT_MD5_HASH_PROP_ID
:
231 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
232 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
, pvData
,
235 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
236 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
237 pCertContext
->pCertInfo
->Subject
.pbData
,
238 pCertContext
->pCertInfo
->Subject
.cbData
,
241 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
242 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
243 pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.pbData
,
244 pCertContext
->pCertInfo
->SubjectPublicKeyInfo
.PublicKey
.cbData
,
247 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID
:
248 ret
= CertContext_GetHashProp(context
, dwPropId
, CALG_MD5
,
249 pCertContext
->pCertInfo
->SerialNumber
.pbData
,
250 pCertContext
->pCertInfo
->SerialNumber
.cbData
,
253 case CERT_SIGNATURE_HASH_PROP_ID
:
254 FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n");
255 SetLastError(CRYPT_E_NOT_FOUND
);
258 SetLastError(CRYPT_E_NOT_FOUND
);
261 TRACE("returning %d\n", ret
);
265 /* info is assumed to be a CRYPT_KEY_PROV_INFO, followed by its container name,
266 * provider name, and any provider parameters, in a contiguous buffer, but
267 * where info's pointers are assumed to be invalid. Upon return, info's
268 * pointers point to the appropriate memory locations.
270 static void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info
)
272 DWORD i
, containerLen
, provNameLen
;
273 LPBYTE data
= (LPBYTE
)info
+ sizeof(CRYPT_KEY_PROV_INFO
);
275 info
->pwszContainerName
= (LPWSTR
)data
;
276 containerLen
= (lstrlenW(info
->pwszContainerName
) + 1) * sizeof(WCHAR
);
277 data
+= containerLen
;
279 info
->pwszProvName
= (LPWSTR
)data
;
280 provNameLen
= (lstrlenW(info
->pwszProvName
) + 1) * sizeof(WCHAR
);
283 info
->rgProvParam
= (PCRYPT_KEY_PROV_PARAM
)data
;
284 data
+= info
->cProvParam
* sizeof(CRYPT_KEY_PROV_PARAM
);
286 for (i
= 0; i
< info
->cProvParam
; i
++)
288 info
->rgProvParam
[i
].pbData
= data
;
289 data
+= info
->rgProvParam
[i
].cbData
;
293 BOOL WINAPI
CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
294 DWORD dwPropId
, void *pvData
, DWORD
*pcbData
)
298 TRACE("(%p, %ld, %p, %p)\n", pCertContext
, dwPropId
, pvData
, pcbData
);
303 case CERT_CERT_PROP_ID
:
304 case CERT_CRL_PROP_ID
:
305 case CERT_CTL_PROP_ID
:
306 SetLastError(E_INVALIDARG
);
309 case CERT_ACCESS_STATE_PROP_ID
:
312 *pcbData
= sizeof(DWORD
);
315 else if (*pcbData
< sizeof(DWORD
))
317 SetLastError(ERROR_MORE_DATA
);
318 *pcbData
= sizeof(DWORD
);
324 CertStore_GetAccessState(pCertContext
->hCertStore
);
328 case CERT_KEY_PROV_INFO_PROP_ID
:
329 ret
= CertContext_GetProperty((void *)pCertContext
, dwPropId
, pvData
,
332 CRYPT_FixKeyProvInfoPointers((PCRYPT_KEY_PROV_INFO
)pvData
);
335 ret
= CertContext_GetProperty((void *)pCertContext
, dwPropId
, pvData
,
339 TRACE("returning %d\n", ret
);
343 /* Copies key provider info from from into to, where to is assumed to be a
344 * contiguous buffer of memory large enough for from and all its associated
345 * data, but whose pointers are uninitialized.
346 * Upon return, to contains a contiguous copy of from, packed in the following
348 * - CRYPT_KEY_PROV_INFO
349 * - pwszContainerName
351 * - rgProvParam[0]...
353 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to
,
354 PCRYPT_KEY_PROV_INFO from
)
357 LPBYTE nextData
= (LPBYTE
)to
+ sizeof(CRYPT_KEY_PROV_INFO
);
359 to
->pwszContainerName
= (LPWSTR
)nextData
;
360 lstrcpyW(to
->pwszContainerName
, from
->pwszContainerName
);
361 nextData
+= (lstrlenW(from
->pwszContainerName
) + 1) * sizeof(WCHAR
);
362 to
->pwszProvName
= (LPWSTR
)nextData
;
363 lstrcpyW(to
->pwszProvName
, from
->pwszProvName
);
364 nextData
+= (lstrlenW(from
->pwszProvName
) + 1) * sizeof(WCHAR
);
365 to
->dwProvType
= from
->dwProvType
;
366 to
->dwFlags
= from
->dwFlags
;
367 to
->cProvParam
= from
->cProvParam
;
368 to
->rgProvParam
= (PCRYPT_KEY_PROV_PARAM
)nextData
;
369 nextData
+= to
->cProvParam
* sizeof(CRYPT_KEY_PROV_PARAM
);
370 to
->dwKeySpec
= from
->dwKeySpec
;
371 for (i
= 0; i
< to
->cProvParam
; i
++)
373 memcpy(&to
->rgProvParam
[i
], &from
->rgProvParam
[i
],
374 sizeof(CRYPT_KEY_PROV_PARAM
));
375 to
->rgProvParam
[i
].pbData
= nextData
;
376 memcpy(to
->rgProvParam
[i
].pbData
, from
->rgProvParam
[i
].pbData
,
377 from
->rgProvParam
[i
].cbData
);
378 nextData
+= from
->rgProvParam
[i
].cbData
;
382 static BOOL
CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties
,
383 PCRYPT_KEY_PROV_INFO info
)
387 DWORD size
= sizeof(CRYPT_KEY_PROV_INFO
), i
, containerSize
, provNameSize
;
389 containerSize
= (lstrlenW(info
->pwszContainerName
) + 1) * sizeof(WCHAR
);
390 provNameSize
= (lstrlenW(info
->pwszProvName
) + 1) * sizeof(WCHAR
);
391 size
+= containerSize
+ provNameSize
;
392 for (i
= 0; i
< info
->cProvParam
; i
++)
393 size
+= sizeof(CRYPT_KEY_PROV_PARAM
) + info
->rgProvParam
[i
].cbData
;
394 buf
= CryptMemAlloc(size
);
397 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO
)buf
, info
);
398 ret
= ContextPropertyList_SetProperty(properties
,
399 CERT_KEY_PROV_INFO_PROP_ID
, buf
, size
);
407 static BOOL WINAPI
CertContext_SetProperty(void *context
, DWORD dwPropId
,
408 DWORD dwFlags
, const void *pvData
)
410 PCONTEXT_PROPERTY_LIST properties
=
411 Context_GetProperties(context
, sizeof(CERT_CONTEXT
));
414 TRACE("(%p, %ld, %08lx, %p)\n", context
, dwPropId
, dwFlags
, pvData
);
420 ContextPropertyList_RemoveProperty(properties
, dwPropId
);
427 case CERT_AUTO_ENROLL_PROP_ID
:
428 case CERT_CTL_USAGE_PROP_ID
: /* same as CERT_ENHKEY_USAGE_PROP_ID */
429 case CERT_DESCRIPTION_PROP_ID
:
430 case CERT_FRIENDLY_NAME_PROP_ID
:
431 case CERT_HASH_PROP_ID
:
432 case CERT_KEY_IDENTIFIER_PROP_ID
:
433 case CERT_MD5_HASH_PROP_ID
:
434 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
435 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
436 case CERT_PVK_FILE_PROP_ID
:
437 case CERT_SIGNATURE_HASH_PROP_ID
:
438 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
439 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
:
440 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
441 case CERT_ENROLLMENT_PROP_ID
:
442 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
443 case CERT_RENEWAL_PROP_ID
:
445 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvData
;
447 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
448 blob
->pbData
, blob
->cbData
);
451 case CERT_DATE_STAMP_PROP_ID
:
452 ret
= ContextPropertyList_SetProperty(properties
, dwPropId
,
453 (LPBYTE
)pvData
, sizeof(FILETIME
));
455 case CERT_KEY_PROV_INFO_PROP_ID
:
456 ret
= CertContext_SetKeyProvInfoProperty(properties
,
457 (PCRYPT_KEY_PROV_INFO
)pvData
);
460 FIXME("%ld: stub\n", dwPropId
);
464 TRACE("returning %d\n", ret
);
468 BOOL WINAPI
CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext
,
469 DWORD dwPropId
, DWORD dwFlags
, const void *pvData
)
473 TRACE("(%p, %ld, %08lx, %p)\n", pCertContext
, dwPropId
, dwFlags
, pvData
);
475 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
476 * crashes on most of these, I'll be safer.
481 case CERT_ACCESS_STATE_PROP_ID
:
482 case CERT_CERT_PROP_ID
:
483 case CERT_CRL_PROP_ID
:
484 case CERT_CTL_PROP_ID
:
485 SetLastError(E_INVALIDARG
);
488 ret
= CertContext_SetProperty((void *)pCertContext
, dwPropId
, dwFlags
,
490 TRACE("returning %d\n", ret
);
494 BOOL WINAPI
CertCompareCertificate(DWORD dwCertEncodingType
,
495 PCERT_INFO pCertId1
, PCERT_INFO pCertId2
)
497 TRACE("(%08lx, %p, %p)\n", dwCertEncodingType
, pCertId1
, pCertId2
);
499 return CertCompareCertificateName(dwCertEncodingType
, &pCertId1
->Issuer
,
500 &pCertId2
->Issuer
) && CertCompareIntegerBlob(&pCertId1
->SerialNumber
,
501 &pCertId2
->SerialNumber
);
504 BOOL WINAPI
CertCompareCertificateName(DWORD dwCertEncodingType
,
505 PCERT_NAME_BLOB pCertName1
, PCERT_NAME_BLOB pCertName2
)
509 TRACE("(%08lx, %p, %p)\n", dwCertEncodingType
, pCertName1
, pCertName2
);
511 if (pCertName1
->cbData
== pCertName2
->cbData
)
513 if (pCertName1
->cbData
)
514 ret
= !memcmp(pCertName1
->pbData
, pCertName2
->pbData
,
524 /* Returns the number of significant bytes in pInt, where a byte is
525 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
526 * for negative numbers. pInt is assumed to be little-endian.
528 static DWORD
CRYPT_significantBytes(PCRYPT_INTEGER_BLOB pInt
)
530 DWORD ret
= pInt
->cbData
;
534 if (pInt
->pbData
[ret
- 2] <= 0x7f && pInt
->pbData
[ret
- 1] == 0)
536 else if (pInt
->pbData
[ret
- 2] >= 0x80 && pInt
->pbData
[ret
- 1] == 0xff)
544 BOOL WINAPI
CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1
,
545 PCRYPT_INTEGER_BLOB pInt2
)
550 TRACE("(%p, %p)\n", pInt1
, pInt2
);
552 cb1
= CRYPT_significantBytes(pInt1
);
553 cb2
= CRYPT_significantBytes(pInt2
);
557 ret
= !memcmp(pInt1
->pbData
, pInt1
->pbData
, cb1
);
566 BOOL WINAPI
CertComparePublicKeyInfo(DWORD dwCertEncodingType
,
567 PCERT_PUBLIC_KEY_INFO pPublicKey1
, PCERT_PUBLIC_KEY_INFO pPublicKey2
)
571 TRACE("(%08lx, %p, %p)\n", dwCertEncodingType
, pPublicKey1
, pPublicKey2
);
573 if (pPublicKey1
->PublicKey
.cbData
== pPublicKey2
->PublicKey
.cbData
&&
574 pPublicKey1
->PublicKey
.cUnusedBits
== pPublicKey2
->PublicKey
.cUnusedBits
)
576 if (pPublicKey2
->PublicKey
.cbData
)
577 ret
= !memcmp(pPublicKey1
->PublicKey
.pbData
,
578 pPublicKey2
->PublicKey
.pbData
, pPublicKey1
->PublicKey
.cbData
);
587 typedef BOOL (*CertCompareFunc
)(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
588 DWORD dwFlags
, const void *pvPara
);
590 static BOOL
compare_cert_any(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
591 DWORD dwFlags
, const void *pvPara
)
596 static BOOL
compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
597 DWORD dwFlags
, const void *pvPara
)
601 DWORD size
= sizeof(hash
);
603 ret
= CertGetCertificateContextProperty(pCertContext
,
604 CERT_MD5_HASH_PROP_ID
, hash
, &size
);
607 const CRYPT_HASH_BLOB
*pHash
= (const CRYPT_HASH_BLOB
*)pvPara
;
609 if (size
== pHash
->cbData
)
610 ret
= !memcmp(pHash
->pbData
, hash
, size
);
617 static BOOL
compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
618 DWORD dwFlags
, const void *pvPara
)
622 DWORD size
= sizeof(hash
);
624 ret
= CertGetCertificateContextProperty(pCertContext
,
625 CERT_SHA1_HASH_PROP_ID
, hash
, &size
);
628 const CRYPT_HASH_BLOB
*pHash
= (const CRYPT_HASH_BLOB
*)pvPara
;
630 if (size
== pHash
->cbData
)
631 ret
= !memcmp(pHash
->pbData
, hash
, size
);
638 static BOOL
compare_cert_by_name(PCCERT_CONTEXT pCertContext
, DWORD dwType
,
639 DWORD dwFlags
, const void *pvPara
)
641 CERT_NAME_BLOB
*blob
= (CERT_NAME_BLOB
*)pvPara
, *toCompare
;
644 if (dwType
& CERT_INFO_SUBJECT_FLAG
)
645 toCompare
= &pCertContext
->pCertInfo
->Subject
;
647 toCompare
= &pCertContext
->pCertInfo
->Issuer
;
648 ret
= CertCompareCertificateName(pCertContext
->dwCertEncodingType
,
653 static BOOL
compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext
,
654 DWORD dwType
, DWORD dwFlags
, const void *pvPara
)
656 CERT_INFO
*pCertInfo
= (CERT_INFO
*)pvPara
;
658 return CertCompareCertificateName(pCertContext
->dwCertEncodingType
,
659 &pCertInfo
->Issuer
, &pCertContext
->pCertInfo
->Subject
);
662 static BOOL
compare_cert_by_issuer(PCCERT_CONTEXT pCertContext
,
663 DWORD dwType
, DWORD dwFlags
, const void *pvPara
)
665 return compare_cert_by_subject_cert(pCertContext
, dwType
, dwFlags
,
666 ((PCCERT_CONTEXT
)pvPara
)->pCertInfo
);
669 PCCERT_CONTEXT WINAPI
CertFindCertificateInStore(HCERTSTORE hCertStore
,
670 DWORD dwCertEncodingType
, DWORD dwFlags
, DWORD dwType
, const void *pvPara
,
671 PCCERT_CONTEXT pPrevCertContext
)
674 CertCompareFunc compare
;
676 TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore
, dwCertEncodingType
,
677 dwFlags
, dwType
, pvPara
, pPrevCertContext
);
679 switch (dwType
>> CERT_COMPARE_SHIFT
)
681 case CERT_COMPARE_ANY
:
682 compare
= compare_cert_any
;
684 case CERT_COMPARE_MD5_HASH
:
685 compare
= compare_cert_by_md5_hash
;
687 case CERT_COMPARE_SHA1_HASH
:
688 compare
= compare_cert_by_sha1_hash
;
690 case CERT_COMPARE_NAME
:
691 compare
= compare_cert_by_name
;
693 case CERT_COMPARE_SUBJECT_CERT
:
694 compare
= compare_cert_by_subject_cert
;
696 case CERT_COMPARE_ISSUER_OF
:
697 compare
= compare_cert_by_issuer
;
700 FIXME("find type %08lx unimplemented\n", dwType
);
706 BOOL matches
= FALSE
;
708 ret
= pPrevCertContext
;
710 ret
= CertEnumCertificatesInStore(hCertStore
, ret
);
712 matches
= compare(ret
, dwType
, dwFlags
, pvPara
);
713 } while (ret
!= NULL
&& !matches
);
715 SetLastError(CRYPT_E_NOT_FOUND
);
719 SetLastError(CRYPT_E_NOT_FOUND
);
725 PCCERT_CONTEXT WINAPI
CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore
,
726 DWORD dwCertEncodingType
, PCERT_INFO pCertId
)
728 TRACE("(%p, %08lx, %p)\n", hCertStore
, dwCertEncodingType
, pCertId
);
732 SetLastError(E_INVALIDARG
);
735 return CertFindCertificateInStore(hCertStore
, dwCertEncodingType
, 0,
736 CERT_FIND_SUBJECT_CERT
, pCertId
, NULL
);
739 BOOL WINAPI
CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject
,
740 PCCERT_CONTEXT pIssuer
, DWORD
*pdwFlags
)
742 static const DWORD supportedFlags
= CERT_STORE_REVOCATION_FLAG
|
743 CERT_STORE_SIGNATURE_FLAG
| CERT_STORE_TIME_VALIDITY_FLAG
;
745 if (*pdwFlags
& ~supportedFlags
)
747 SetLastError(E_INVALIDARG
);
750 if (*pdwFlags
& CERT_STORE_REVOCATION_FLAG
)
752 PCCRL_CONTEXT crl
= CertFindCRLInStore(pSubject
->hCertStore
,
753 pSubject
->dwCertEncodingType
, 0, CRL_FIND_ISSUED_BY
, pSubject
, NULL
);
757 FIXME("check CRL for subject\n");
760 *pdwFlags
|= CERT_STORE_NO_CRL_FLAG
;
762 if (*pdwFlags
& CERT_STORE_TIME_VALIDITY_FLAG
)
764 if (0 == CertVerifyTimeValidity(NULL
, pSubject
->pCertInfo
))
765 *pdwFlags
&= ~CERT_STORE_TIME_VALIDITY_FLAG
;
767 if (*pdwFlags
& CERT_STORE_SIGNATURE_FLAG
)
769 if (CryptVerifyCertificateSignatureEx(0, pSubject
->dwCertEncodingType
,
770 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
, (void *)pSubject
,
771 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
, (void *)pIssuer
, 0, NULL
))
772 *pdwFlags
&= ~CERT_STORE_SIGNATURE_FLAG
;
777 PCCERT_CONTEXT WINAPI
CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore
,
778 PCCERT_CONTEXT pSubjectContext
, PCCERT_CONTEXT pPrevIssuerContext
,
783 TRACE("(%p, %p, %p, %08lx)\n", hCertStore
, pSubjectContext
,
784 pPrevIssuerContext
, *pdwFlags
);
786 if (!pSubjectContext
)
788 SetLastError(E_INVALIDARG
);
792 ret
= CertFindCertificateInStore(hCertStore
,
793 pSubjectContext
->dwCertEncodingType
, 0, CERT_FIND_ISSUER_OF
,
794 pSubjectContext
, pPrevIssuerContext
);
797 if (!CertVerifySubjectCertificateContext(pSubjectContext
, ret
,
800 CertFreeCertificateContext(ret
);
808 PCRYPT_ATTRIBUTE WINAPI
CertFindAttribute(LPCSTR pszObjId
, DWORD cAttr
,
809 CRYPT_ATTRIBUTE rgAttr
[])
811 PCRYPT_ATTRIBUTE ret
= NULL
;
814 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cAttr
, rgAttr
);
820 SetLastError(ERROR_INVALID_PARAMETER
);
824 for (i
= 0; !ret
&& i
< cAttr
; i
++)
825 if (rgAttr
[i
].pszObjId
&& !strcmp(pszObjId
, rgAttr
[i
].pszObjId
))
830 PCERT_EXTENSION WINAPI
CertFindExtension(LPCSTR pszObjId
, DWORD cExtensions
,
831 CERT_EXTENSION rgExtensions
[])
833 PCERT_EXTENSION ret
= NULL
;
836 TRACE("%s %ld %p\n", debugstr_a(pszObjId
), cExtensions
, rgExtensions
);
842 SetLastError(ERROR_INVALID_PARAMETER
);
846 for (i
= 0; !ret
&& i
< cExtensions
; i
++)
847 if (rgExtensions
[i
].pszObjId
&& !strcmp(pszObjId
,
848 rgExtensions
[i
].pszObjId
))
849 ret
= &rgExtensions
[i
];
853 PCERT_RDN_ATTR WINAPI
CertFindRDNAttr(LPCSTR pszObjId
, PCERT_NAME_INFO pName
)
855 PCERT_RDN_ATTR ret
= NULL
;
858 TRACE("%s %p\n", debugstr_a(pszObjId
), pName
);
862 SetLastError(ERROR_INVALID_PARAMETER
);
866 for (i
= 0; !ret
&& i
< pName
->cRDN
; i
++)
867 for (j
= 0; !ret
&& j
< pName
->rgRDN
[i
].cRDNAttr
; j
++)
868 if (pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
&& !strcmp(pszObjId
,
869 pName
->rgRDN
[i
].rgRDNAttr
[j
].pszObjId
))
870 ret
= &pName
->rgRDN
[i
].rgRDNAttr
[j
];
874 LONG WINAPI
CertVerifyTimeValidity(LPFILETIME pTimeToVerify
,
875 PCERT_INFO pCertInfo
)
884 GetSystemTime(&sysTime
);
885 SystemTimeToFileTime(&sysTime
, &fileTime
);
886 pTimeToVerify
= &fileTime
;
888 if ((ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotBefore
)) >= 0)
890 ret
= CompareFileTime(pTimeToVerify
, &pCertInfo
->NotAfter
);
897 BOOL WINAPI
CryptHashCertificate(HCRYPTPROV hCryptProv
, ALG_ID Algid
,
898 DWORD dwFlags
, const BYTE
*pbEncoded
, DWORD cbEncoded
, BYTE
*pbComputedHash
,
899 DWORD
*pcbComputedHash
)
902 HCRYPTHASH hHash
= 0;
904 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv
, Algid
, dwFlags
,
905 pbEncoded
, cbEncoded
, pbComputedHash
, pcbComputedHash
);
908 hCryptProv
= CRYPT_GetDefaultProvider();
913 ret
= CryptCreateHash(hCryptProv
, Algid
, 0, 0, &hHash
);
916 ret
= CryptHashData(hHash
, pbEncoded
, cbEncoded
, 0);
918 ret
= CryptGetHashParam(hHash
, HP_HASHVAL
, pbComputedHash
,
920 CryptDestroyHash(hHash
);
926 BOOL WINAPI
CryptSignCertificate(HCRYPTPROV hCryptProv
, DWORD dwKeySpec
,
927 DWORD dwCertEncodingType
, const BYTE
*pbEncodedToBeSigned
,
928 DWORD cbEncodedToBeSigned
, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
,
929 const void *pvHashAuxInfo
, BYTE
*pbSignature
, DWORD
*pcbSignature
)
935 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv
,
936 dwKeySpec
, dwCertEncodingType
, pbEncodedToBeSigned
, cbEncodedToBeSigned
,
937 pSignatureAlgorithm
, pvHashAuxInfo
, pbSignature
, pcbSignature
);
939 algID
= CertOIDToAlgId(pSignatureAlgorithm
->pszObjId
);
942 SetLastError(NTE_BAD_ALGID
);
947 SetLastError(ERROR_INVALID_PARAMETER
);
951 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hHash
);
954 ret
= CryptHashData(hHash
, pbEncodedToBeSigned
, cbEncodedToBeSigned
, 0);
956 ret
= CryptSignHashW(hHash
, dwKeySpec
, NULL
, 0, pbSignature
,
958 CryptDestroyHash(hHash
);
963 BOOL WINAPI
CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv
,
964 DWORD dwCertEncodingType
, const BYTE
*pbEncoded
, DWORD cbEncoded
,
965 PCERT_PUBLIC_KEY_INFO pPublicKey
)
967 return CryptVerifyCertificateSignatureEx(hCryptProv
, dwCertEncodingType
,
968 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
, (void *)pbEncoded
,
969 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
, pPublicKey
, 0, NULL
);
972 static BOOL
CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv
,
973 DWORD dwCertEncodingType
, PCERT_PUBLIC_KEY_INFO pubKeyInfo
,
974 PCERT_SIGNED_CONTENT_INFO signedCert
)
977 ALG_ID algID
= CertOIDToAlgId(pubKeyInfo
->Algorithm
.pszObjId
);
980 /* Load the default provider if necessary */
982 hCryptProv
= CRYPT_GetDefaultProvider();
983 ret
= CryptImportPublicKeyInfoEx(hCryptProv
, dwCertEncodingType
,
984 pubKeyInfo
, algID
, 0, NULL
, &key
);
989 /* Some key algorithms aren't hash algorithms, so map them */
990 if (algID
== CALG_RSA_SIGN
|| algID
== CALG_RSA_KEYX
)
992 ret
= CryptCreateHash(hCryptProv
, algID
, 0, 0, &hash
);
995 ret
= CryptHashData(hash
, signedCert
->ToBeSigned
.pbData
,
996 signedCert
->ToBeSigned
.cbData
, 0);
998 ret
= CryptVerifySignatureW(hash
, signedCert
->Signature
.pbData
,
999 signedCert
->Signature
.cbData
, key
, NULL
, 0);
1000 CryptDestroyHash(hash
);
1002 CryptDestroyKey(key
);
1007 BOOL WINAPI
CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv
,
1008 DWORD dwCertEncodingType
, DWORD dwSubjectType
, void *pvSubject
,
1009 DWORD dwIssuerType
, void *pvIssuer
, DWORD dwFlags
, void *pvReserved
)
1012 CRYPT_DATA_BLOB subjectBlob
;
1014 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv
,
1015 dwCertEncodingType
, dwSubjectType
, pvSubject
, dwIssuerType
, pvIssuer
,
1016 dwFlags
, pvReserved
);
1018 switch (dwSubjectType
)
1020 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB
:
1022 PCRYPT_DATA_BLOB blob
= (PCRYPT_DATA_BLOB
)pvSubject
;
1024 subjectBlob
.pbData
= blob
->pbData
;
1025 subjectBlob
.cbData
= blob
->cbData
;
1028 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
:
1030 PCERT_CONTEXT context
= (PCERT_CONTEXT
)pvSubject
;
1032 subjectBlob
.pbData
= context
->pbCertEncoded
;
1033 subjectBlob
.cbData
= context
->cbCertEncoded
;
1036 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL
:
1038 PCRL_CONTEXT context
= (PCRL_CONTEXT
)pvSubject
;
1040 subjectBlob
.pbData
= context
->pbCrlEncoded
;
1041 subjectBlob
.cbData
= context
->cbCrlEncoded
;
1045 SetLastError(E_INVALIDARG
);
1051 PCERT_SIGNED_CONTENT_INFO signedCert
= NULL
;
1054 ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_CERT
,
1055 subjectBlob
.pbData
, subjectBlob
.cbData
,
1056 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
1057 (BYTE
*)&signedCert
, &size
);
1060 switch (dwIssuerType
)
1062 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY
:
1063 ret
= CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv
,
1064 dwCertEncodingType
, (PCERT_PUBLIC_KEY_INFO
)pvIssuer
,
1067 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
:
1068 ret
= CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv
,
1070 &((PCCERT_CONTEXT
)pvIssuer
)->pCertInfo
->SubjectPublicKeyInfo
,
1073 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN
:
1074 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
1077 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL
:
1080 SetLastError(E_INVALIDARG
);
1085 FIXME("unimplemented for NULL signer\n");
1086 SetLastError(E_INVALIDARG
);
1091 SetLastError(E_INVALIDARG
);
1094 LocalFree(signedCert
);
1100 BOOL WINAPI
CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext
, DWORD dwFlags
,
1101 PCERT_ENHKEY_USAGE pUsage
, DWORD
*pcbUsage
)
1103 PCERT_ENHKEY_USAGE usage
= NULL
;
1107 if (!pCertContext
|| !pcbUsage
)
1109 SetLastError(ERROR_INVALID_PARAMETER
);
1113 TRACE("(%p, %08lx, %p, %ld)\n", pCertContext
, dwFlags
, pUsage
, *pcbUsage
);
1115 if (!(dwFlags
& CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
))
1119 if (CertGetCertificateContextProperty(pCertContext
,
1120 CERT_ENHKEY_USAGE_PROP_ID
, NULL
, &propSize
))
1122 LPBYTE buf
= CryptMemAlloc(propSize
);
1126 if (CertGetCertificateContextProperty(pCertContext
,
1127 CERT_ENHKEY_USAGE_PROP_ID
, buf
, &propSize
))
1129 ret
= CryptDecodeObjectEx(pCertContext
->dwCertEncodingType
,
1130 X509_ENHANCED_KEY_USAGE
, buf
, propSize
,
1131 CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &usage
, &bytesNeeded
);
1137 if (!usage
&& !(dwFlags
& CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
))
1139 PCERT_EXTENSION ext
= CertFindExtension(szOID_ENHANCED_KEY_USAGE
,
1140 pCertContext
->pCertInfo
->cExtension
,
1141 pCertContext
->pCertInfo
->rgExtension
);
1145 ret
= CryptDecodeObjectEx(pCertContext
->dwCertEncodingType
,
1146 X509_ENHANCED_KEY_USAGE
, ext
->Value
.pbData
, ext
->Value
.cbData
,
1147 CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &usage
, &bytesNeeded
);
1152 /* If a particular location is specified, this should fail. Otherwise
1153 * it should succeed with an empty usage. (This is true on Win2k and
1154 * later, which we emulate.)
1158 SetLastError(CRYPT_E_NOT_FOUND
);
1162 bytesNeeded
= sizeof(CERT_ENHKEY_USAGE
);
1168 *pcbUsage
= bytesNeeded
;
1169 else if (*pcbUsage
< bytesNeeded
)
1171 SetLastError(ERROR_MORE_DATA
);
1172 *pcbUsage
= bytesNeeded
;
1177 *pcbUsage
= bytesNeeded
;
1181 LPSTR nextOID
= (LPSTR
)((LPBYTE
)pUsage
+
1182 sizeof(CERT_ENHKEY_USAGE
) +
1183 usage
->cUsageIdentifier
* sizeof(LPSTR
));
1185 pUsage
->cUsageIdentifier
= usage
->cUsageIdentifier
;
1186 pUsage
->rgpszUsageIdentifier
= (LPSTR
*)((LPBYTE
)pUsage
+
1187 sizeof(CERT_ENHKEY_USAGE
));
1188 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
1190 pUsage
->rgpszUsageIdentifier
[i
] = nextOID
;
1191 strcpy(nextOID
, usage
->rgpszUsageIdentifier
[i
]);
1192 nextOID
+= strlen(nextOID
) + 1;
1196 pUsage
->cUsageIdentifier
= 0;
1201 TRACE("returning %d\n", ret
);
1205 BOOL WINAPI
CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext
,
1206 PCERT_ENHKEY_USAGE pUsage
)
1210 TRACE("(%p, %p)\n", pCertContext
, pUsage
);
1214 CRYPT_DATA_BLOB blob
= { 0, NULL
};
1216 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_ENHANCED_KEY_USAGE
,
1217 pUsage
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
, &blob
.pbData
, &blob
.cbData
);
1220 ret
= CertSetCertificateContextProperty(pCertContext
,
1221 CERT_ENHKEY_USAGE_PROP_ID
, 0, &blob
);
1222 LocalFree(blob
.pbData
);
1226 ret
= CertSetCertificateContextProperty(pCertContext
,
1227 CERT_ENHKEY_USAGE_PROP_ID
, 0, NULL
);
1231 BOOL WINAPI
CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext
,
1232 LPCSTR pszUsageIdentifier
)
1237 TRACE("(%p, %s)\n", pCertContext
, debugstr_a(pszUsageIdentifier
));
1239 if (CertGetEnhancedKeyUsage(pCertContext
,
1240 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, NULL
, &size
))
1242 PCERT_ENHKEY_USAGE usage
= CryptMemAlloc(size
);
1246 ret
= CertGetEnhancedKeyUsage(pCertContext
,
1247 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, usage
, &size
);
1250 PCERT_ENHKEY_USAGE newUsage
= CryptMemAlloc(size
+
1251 sizeof(LPSTR
) + strlen(pszUsageIdentifier
) + 1);
1258 newUsage
->rgpszUsageIdentifier
=
1259 (LPSTR
*)((LPBYTE
)newUsage
+ sizeof(CERT_ENHKEY_USAGE
));
1260 nextOID
= (LPSTR
)((LPBYTE
)newUsage
->rgpszUsageIdentifier
+
1261 (usage
->cUsageIdentifier
+ 1) * sizeof(LPSTR
));
1262 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
1264 newUsage
->rgpszUsageIdentifier
[i
] = nextOID
;
1265 strcpy(nextOID
, usage
->rgpszUsageIdentifier
[i
]);
1266 nextOID
+= strlen(nextOID
) + 1;
1268 newUsage
->rgpszUsageIdentifier
[i
] = nextOID
;
1269 strcpy(nextOID
, pszUsageIdentifier
);
1270 newUsage
->cUsageIdentifier
= i
+ 1;
1271 ret
= CertSetEnhancedKeyUsage(pCertContext
, newUsage
);
1272 CryptMemFree(newUsage
);
1275 CryptMemFree(usage
);
1282 PCERT_ENHKEY_USAGE usage
= CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE
) +
1283 sizeof(LPSTR
) + strlen(pszUsageIdentifier
) + 1);
1287 usage
->rgpszUsageIdentifier
=
1288 (LPSTR
*)((LPBYTE
)usage
+ sizeof(CERT_ENHKEY_USAGE
));
1289 usage
->rgpszUsageIdentifier
[0] = (LPSTR
)((LPBYTE
)usage
+
1290 sizeof(CERT_ENHKEY_USAGE
) + sizeof(LPSTR
));
1291 strcpy(usage
->rgpszUsageIdentifier
[0], pszUsageIdentifier
);
1292 usage
->cUsageIdentifier
= 1;
1293 ret
= CertSetEnhancedKeyUsage(pCertContext
, usage
);
1294 CryptMemFree(usage
);
1302 BOOL WINAPI
CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext
,
1303 LPCSTR pszUsageIdentifier
)
1307 CERT_ENHKEY_USAGE usage
;
1309 TRACE("(%p, %s)\n", pCertContext
, debugstr_a(pszUsageIdentifier
));
1311 size
= sizeof(usage
);
1312 ret
= CertGetEnhancedKeyUsage(pCertContext
,
1313 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, &usage
, &size
);
1314 if (!ret
&& GetLastError() == ERROR_MORE_DATA
)
1316 PCERT_ENHKEY_USAGE pUsage
= CryptMemAlloc(size
);
1320 ret
= CertGetEnhancedKeyUsage(pCertContext
,
1321 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG
, pUsage
, &size
);
1324 if (pUsage
->cUsageIdentifier
)
1329 for (i
= 0; i
< pUsage
->cUsageIdentifier
; i
++)
1331 if (!strcmp(pUsage
->rgpszUsageIdentifier
[i
],
1332 pszUsageIdentifier
))
1334 if (found
&& i
< pUsage
->cUsageIdentifier
- 1)
1335 pUsage
->rgpszUsageIdentifier
[i
] =
1336 pUsage
->rgpszUsageIdentifier
[i
+ 1];
1338 pUsage
->cUsageIdentifier
--;
1339 /* Remove the usage if it's empty */
1340 if (pUsage
->cUsageIdentifier
)
1341 ret
= CertSetEnhancedKeyUsage(pCertContext
, pUsage
);
1343 ret
= CertSetEnhancedKeyUsage(pCertContext
, NULL
);
1346 CryptMemFree(pUsage
);
1353 /* it fit in an empty usage, therefore there's nothing to remove */
1359 BOOL WINAPI
CertGetValidUsages(DWORD cCerts
, PCCERT_CONTEXT
*rghCerts
,
1360 int *cNumOIDSs
, LPSTR
*rghOIDs
, DWORD
*pcbOIDs
)
1363 DWORD i
, cbOIDs
= 0;
1364 BOOL allUsagesValid
= TRUE
;
1365 CERT_ENHKEY_USAGE validUsages
= { 0, NULL
};
1367 TRACE("(%ld, %p, %p, %p, %ld)\n", cCerts
, *rghCerts
, cNumOIDSs
,
1370 for (i
= 0; ret
&& i
< cCerts
; i
++)
1372 CERT_ENHKEY_USAGE usage
;
1373 DWORD size
= sizeof(usage
);
1375 ret
= CertGetEnhancedKeyUsage(rghCerts
[i
], 0, &usage
, &size
);
1376 /* Success is deliberately ignored: it implies all usages are valid */
1377 if (!ret
&& GetLastError() == ERROR_MORE_DATA
)
1379 PCERT_ENHKEY_USAGE pUsage
= CryptMemAlloc(size
);
1381 allUsagesValid
= FALSE
;
1384 ret
= CertGetEnhancedKeyUsage(rghCerts
[i
], 0, pUsage
, &size
);
1387 if (!validUsages
.cUsageIdentifier
)
1391 cbOIDs
= pUsage
->cUsageIdentifier
* sizeof(LPSTR
);
1392 validUsages
.cUsageIdentifier
= pUsage
->cUsageIdentifier
;
1393 for (j
= 0; j
< validUsages
.cUsageIdentifier
; j
++)
1394 cbOIDs
+= lstrlenA(pUsage
->rgpszUsageIdentifier
[j
])
1396 validUsages
.rgpszUsageIdentifier
=
1397 CryptMemAlloc(cbOIDs
);
1398 if (validUsages
.rgpszUsageIdentifier
)
1400 LPSTR nextOID
= (LPSTR
)
1401 ((LPBYTE
)validUsages
.rgpszUsageIdentifier
+
1402 validUsages
.cUsageIdentifier
* sizeof(LPSTR
));
1404 for (j
= 0; j
< validUsages
.cUsageIdentifier
; j
++)
1406 validUsages
.rgpszUsageIdentifier
[j
] = nextOID
;
1407 lstrcpyA(validUsages
.rgpszUsageIdentifier
[j
],
1408 pUsage
->rgpszUsageIdentifier
[j
]);
1409 nextOID
+= lstrlenA(nextOID
) + 1;
1417 DWORD j
, k
, validIndexes
= 0, numRemoved
= 0;
1419 /* Merge: build a bitmap of all the indexes of
1420 * validUsages.rgpszUsageIdentifier that are in pUsage.
1422 for (j
= 0; j
< pUsage
->cUsageIdentifier
; j
++)
1424 for (k
= 0; k
< validUsages
.cUsageIdentifier
; k
++)
1426 if (!strcmp(pUsage
->rgpszUsageIdentifier
[j
],
1427 validUsages
.rgpszUsageIdentifier
[k
]))
1429 validIndexes
|= (1 << k
);
1434 /* Merge by removing from validUsages those that are
1435 * not in the bitmap.
1437 for (j
= 0; j
< validUsages
.cUsageIdentifier
; j
++)
1439 if (!(validIndexes
& (1 << j
)))
1441 if (j
< validUsages
.cUsageIdentifier
- 1)
1443 memcpy(&validUsages
.rgpszUsageIdentifier
[j
],
1444 &validUsages
.rgpszUsageIdentifier
[j
+
1446 (validUsages
.cUsageIdentifier
- numRemoved
1447 - j
- 1) * sizeof(LPSTR
));
1449 validUsages
.rgpszUsageIdentifier
[j
]) + 1 +
1454 validUsages
.cUsageIdentifier
--;
1459 CryptMemFree(pUsage
);
1474 if (!rghOIDs
|| *pcbOIDs
< cbOIDs
)
1477 SetLastError(ERROR_MORE_DATA
);
1482 LPSTR nextOID
= (LPSTR
)((LPBYTE
)rghOIDs
+
1483 validUsages
.cUsageIdentifier
* sizeof(LPSTR
));
1486 *cNumOIDSs
= validUsages
.cUsageIdentifier
;
1487 for (i
= 0; i
< validUsages
.cUsageIdentifier
; i
++)
1489 rghOIDs
[i
] = nextOID
;
1490 lstrcpyA(nextOID
, validUsages
.rgpszUsageIdentifier
[i
]);
1491 nextOID
+= lstrlenA(nextOID
) + 1;
1496 CryptMemFree(validUsages
.rgpszUsageIdentifier
);
1500 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
1501 * pInfo is NULL, from the attributes of hProv.
1503 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context
,
1504 PCRYPT_KEY_PROV_INFO pInfo
, HCRYPTPROV hProv
)
1506 CRYPT_KEY_PROV_INFO info
= { 0 };
1514 ret
= CryptGetProvParam(hProv
, PP_CONTAINER
, NULL
, &size
, 0);
1517 LPSTR szContainer
= CryptMemAlloc(size
);
1521 ret
= CryptGetProvParam(hProv
, PP_CONTAINER
,
1522 (BYTE
*)szContainer
, &size
, 0);
1525 len
= MultiByteToWideChar(CP_ACP
, 0, szContainer
, -1,
1529 info
.pwszContainerName
= CryptMemAlloc(len
*
1531 len
= MultiByteToWideChar(CP_ACP
, 0, szContainer
, -1,
1532 info
.pwszContainerName
, len
);
1535 CryptMemFree(szContainer
);
1538 ret
= CryptGetProvParam(hProv
, PP_NAME
, NULL
, &size
, 0);
1541 LPSTR szProvider
= CryptMemAlloc(size
);
1545 ret
= CryptGetProvParam(hProv
, PP_NAME
, (BYTE
*)szProvider
,
1549 len
= MultiByteToWideChar(CP_ACP
, 0, szProvider
, -1,
1553 info
.pwszProvName
= CryptMemAlloc(len
*
1555 len
= MultiByteToWideChar(CP_ACP
, 0, szProvider
, -1,
1556 info
.pwszProvName
, len
);
1559 CryptMemFree(szProvider
);
1562 size
= sizeof(info
.dwKeySpec
);
1563 ret
= CryptGetProvParam(hProv
, PP_KEYSPEC
, (LPBYTE
)&info
.dwKeySpec
,
1566 info
.dwKeySpec
= AT_SIGNATURE
;
1567 size
= sizeof(info
.dwProvType
);
1568 ret
= CryptGetProvParam(hProv
, PP_PROVTYPE
, (LPBYTE
)&info
.dwProvType
,
1571 info
.dwProvType
= PROV_RSA_FULL
;
1575 ret
= CertSetCertificateContextProperty(context
, CERT_KEY_PROV_INFO_PROP_ID
,
1580 CryptMemFree(info
.pwszContainerName
);
1581 CryptMemFree(info
.pwszProvName
);
1585 /* Creates a signed certificate context from the unsigned, encoded certificate
1586 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
1588 static PCCERT_CONTEXT
CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob
,
1589 HCRYPTPROV hProv
, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo
)
1591 PCCERT_CONTEXT context
= NULL
;
1595 ret
= CryptSignCertificate(hProv
, AT_SIGNATURE
, X509_ASN_ENCODING
,
1596 blob
->pbData
, blob
->cbData
, sigAlgo
, NULL
, NULL
, &sigSize
);
1599 LPBYTE sig
= CryptMemAlloc(sigSize
);
1601 ret
= CryptSignCertificate(hProv
, AT_SIGNATURE
, X509_ASN_ENCODING
,
1602 blob
->pbData
, blob
->cbData
, sigAlgo
, NULL
, sig
, &sigSize
);
1605 CERT_SIGNED_CONTENT_INFO signedInfo
;
1606 BYTE
*encodedSignedCert
= NULL
;
1607 DWORD encodedSignedCertSize
= 0;
1609 signedInfo
.ToBeSigned
.cbData
= blob
->cbData
;
1610 signedInfo
.ToBeSigned
.pbData
= blob
->pbData
;
1611 memcpy(&signedInfo
.SignatureAlgorithm
, sigAlgo
,
1612 sizeof(signedInfo
.SignatureAlgorithm
));
1613 signedInfo
.Signature
.cbData
= sigSize
;
1614 signedInfo
.Signature
.pbData
= sig
;
1615 signedInfo
.Signature
.cUnusedBits
= 0;
1616 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_CERT
,
1617 &signedInfo
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
1618 (BYTE
*)&encodedSignedCert
, &encodedSignedCertSize
);
1621 context
= CertCreateCertificateContext(X509_ASN_ENCODING
,
1622 encodedSignedCert
, encodedSignedCertSize
);
1623 LocalFree(encodedSignedCert
);
1631 /* Copies data from the parameters into info, where:
1632 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
1634 * pSignatureAlgorithm: Optional.
1635 * pStartTime: The starting time of the certificate. If NULL, the current
1636 * system time is used.
1637 * pEndTime: The ending time of the certificate. If NULL, one year past the
1638 * starting time is used.
1639 * pubKey: The public key of the certificate. Must not be NULL.
1640 * pExtensions: Extensions to be included with the certificate. Optional.
1642 static void CRYPT_MakeCertInfo(PCERT_INFO info
,
1643 PCERT_NAME_BLOB pSubjectIssuerBlob
,
1644 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
, PSYSTEMTIME pStartTime
,
1645 PSYSTEMTIME pEndTime
, PCERT_PUBLIC_KEY_INFO pubKey
,
1646 PCERT_EXTENSIONS pExtensions
)
1648 /* FIXME: what serial number to use? */
1649 static const BYTE serialNum
[] = { 1 };
1650 static CHAR oid
[] = szOID_RSA_SHA1RSA
;
1653 assert(pSubjectIssuerBlob
);
1656 info
->dwVersion
= CERT_V3
;
1657 info
->SerialNumber
.cbData
= sizeof(serialNum
);
1658 info
->SerialNumber
.pbData
= (LPBYTE
)serialNum
;
1659 if (pSignatureAlgorithm
)
1660 memcpy(&info
->SignatureAlgorithm
, pSignatureAlgorithm
,
1661 sizeof(info
->SignatureAlgorithm
));
1664 info
->SignatureAlgorithm
.pszObjId
= oid
;
1665 info
->SignatureAlgorithm
.Parameters
.cbData
= 0;
1666 info
->SignatureAlgorithm
.Parameters
.pbData
= NULL
;
1668 info
->Issuer
.cbData
= pSubjectIssuerBlob
->cbData
;
1669 info
->Issuer
.pbData
= pSubjectIssuerBlob
->pbData
;
1671 SystemTimeToFileTime(pStartTime
, &info
->NotBefore
);
1673 GetSystemTimeAsFileTime(&info
->NotBefore
);
1675 SystemTimeToFileTime(pStartTime
, &info
->NotAfter
);
1680 if (FileTimeToSystemTime(&info
->NotBefore
, &endTime
))
1683 SystemTimeToFileTime(&endTime
, &info
->NotAfter
);
1686 info
->Subject
.cbData
= pSubjectIssuerBlob
->cbData
;
1687 info
->Subject
.pbData
= pSubjectIssuerBlob
->pbData
;
1688 memcpy(&info
->SubjectPublicKeyInfo
, pubKey
,
1689 sizeof(info
->SubjectPublicKeyInfo
));
1692 info
->cExtension
= pExtensions
->cExtension
;
1693 info
->rgExtension
= pExtensions
->rgExtension
;
1697 info
->cExtension
= 0;
1698 info
->rgExtension
= NULL
;
1702 typedef RPC_STATUS (RPC_ENTRY
*UuidCreateFunc
)(UUID
*);
1703 typedef RPC_STATUS (RPC_ENTRY
*UuidToStringFunc
)(UUID
*, unsigned char **);
1704 typedef RPC_STATUS (RPC_ENTRY
*RpcStringFreeFunc
)(unsigned char **);
1706 static HCRYPTPROV
CRYPT_CreateKeyProv(void)
1708 HCRYPTPROV hProv
= 0;
1709 HMODULE rpcrt
= LoadLibraryA("rpcrt4");
1713 UuidCreateFunc uuidCreate
= (UuidCreateFunc
)GetProcAddress(rpcrt
,
1715 UuidToStringFunc uuidToString
= (UuidToStringFunc
)GetProcAddress(rpcrt
,
1717 RpcStringFreeFunc rpcStringFree
= (RpcStringFreeFunc
)GetProcAddress(
1718 rpcrt
, "RpcStringFree");
1720 if (uuidCreate
&& uuidToString
&& rpcStringFree
)
1723 RPC_STATUS status
= uuidCreate(&uuid
);
1725 if (status
== RPC_S_OK
|| status
== RPC_S_UUID_LOCAL_ONLY
)
1727 unsigned char *uuidStr
;
1729 status
= uuidToString(&uuid
, &uuidStr
);
1730 if (status
== RPC_S_OK
)
1732 BOOL ret
= CryptAcquireContextA(&hProv
, (LPCSTR
)uuidStr
,
1733 MS_DEF_PROV_A
, PROV_RSA_FULL
, CRYPT_NEWKEYSET
);
1739 ret
= CryptGenKey(hProv
, AT_SIGNATURE
, 0, &key
);
1741 CryptDestroyKey(key
);
1743 rpcStringFree(&uuidStr
);
1752 PCCERT_CONTEXT WINAPI
CertCreateSelfSignCertificate(HCRYPTPROV hProv
,
1753 PCERT_NAME_BLOB pSubjectIssuerBlob
, DWORD dwFlags
,
1754 PCRYPT_KEY_PROV_INFO pKeyProvInfo
,
1755 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm
, PSYSTEMTIME pStartTime
,
1756 PSYSTEMTIME pEndTime
, PCERT_EXTENSIONS pExtensions
)
1758 PCCERT_CONTEXT context
= NULL
;
1759 BOOL ret
, releaseContext
= FALSE
;
1760 PCERT_PUBLIC_KEY_INFO pubKey
= NULL
;
1761 DWORD pubKeySize
= 0;
1763 TRACE("(0x%08lx, %p, %08lx, %p, %p, %p, %p, %p)\n", hProv
,
1764 pSubjectIssuerBlob
, dwFlags
, pKeyProvInfo
, pSignatureAlgorithm
, pStartTime
,
1765 pExtensions
, pExtensions
);
1769 hProv
= CRYPT_CreateKeyProv();
1770 releaseContext
= TRUE
;
1773 CryptExportPublicKeyInfo(hProv
, AT_SIGNATURE
, X509_ASN_ENCODING
, NULL
,
1775 pubKey
= CryptMemAlloc(pubKeySize
);
1778 ret
= CryptExportPublicKeyInfo(hProv
, AT_SIGNATURE
, X509_ASN_ENCODING
,
1779 pubKey
, &pubKeySize
);
1782 CERT_INFO info
= { 0 };
1783 CRYPT_DER_BLOB blob
= { 0, NULL
};
1786 CRYPT_MakeCertInfo(&info
, pSubjectIssuerBlob
, pSignatureAlgorithm
,
1787 pStartTime
, pEndTime
, pubKey
, pExtensions
);
1788 ret
= CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_CERT_TO_BE_SIGNED
,
1789 &info
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
, (BYTE
*)&blob
.pbData
,
1793 if (!(dwFlags
& CERT_CREATE_SELFSIGN_NO_SIGN
))
1794 context
= CRYPT_CreateSignedCert(&blob
, hProv
,
1795 &info
.SignatureAlgorithm
);
1797 context
= CertCreateCertificateContext(X509_ASN_ENCODING
,
1798 blob
.pbData
, blob
.cbData
);
1799 if (context
&& !(dwFlags
& CERT_CREATE_SELFSIGN_NO_KEY_INFO
))
1800 CertContext_SetKeyProvInfo(context
, pKeyProvInfo
, hProv
);
1801 LocalFree(blob
.pbData
);
1804 CryptMemFree(pubKey
);
1807 CryptReleaseContext(hProv
, 0);