2 * Copyright 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
20 #define NONAMELESSUNION
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26 #include "crypt32_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
30 #define DEFAULT_CYCLE_MODULUS 7
32 static HCERTCHAINENGINE CRYPT_defaultChainEngine
;
34 /* This represents a subset of a certificate chain engine: it doesn't include
35 * the "hOther" store described by MSDN, because I'm not sure how that's used.
36 * It also doesn't include the "hTrust" store, because I don't yet implement
37 * CTLs or complex certificate chains.
39 typedef struct _CertificateChainEngine
45 DWORD dwUrlRetrievalTimeout
;
46 DWORD MaximumCachedCertificates
;
47 DWORD CycleDetectionModulus
;
48 } CertificateChainEngine
, *PCertificateChainEngine
;
50 static inline void CRYPT_AddStoresToCollection(HCERTSTORE collection
,
51 DWORD cStores
, HCERTSTORE
*stores
)
55 for (i
= 0; i
< cStores
; i
++)
56 CertAddStoreToCollection(collection
, stores
[i
], 0, 0);
59 static inline void CRYPT_CloseStores(DWORD cStores
, HCERTSTORE
*stores
)
63 for (i
= 0; i
< cStores
; i
++)
64 CertCloseStore(stores
[i
], 0);
67 static const WCHAR rootW
[] = { 'R','o','o','t',0 };
69 static BOOL
CRYPT_CheckRestrictedRoot(HCERTSTORE store
)
75 HCERTSTORE rootStore
= CertOpenSystemStoreW(0, rootW
);
76 PCCERT_CONTEXT cert
= NULL
, check
;
81 cert
= CertEnumCertificatesInStore(store
, cert
);
86 ret
= CertGetCertificateContextProperty(cert
, CERT_HASH_PROP_ID
,
90 CRYPT_HASH_BLOB blob
= { sizeof(hash
), hash
};
92 check
= CertFindCertificateInStore(rootStore
,
93 cert
->dwCertEncodingType
, 0, CERT_FIND_SHA1_HASH
, &blob
,
98 CertFreeCertificateContext(check
);
101 } while (ret
&& cert
);
103 CertFreeCertificateContext(cert
);
104 CertCloseStore(rootStore
, 0);
109 HCERTCHAINENGINE
CRYPT_CreateChainEngine(HCERTSTORE root
,
110 PCERT_CHAIN_ENGINE_CONFIG pConfig
)
112 static const WCHAR caW
[] = { 'C','A',0 };
113 static const WCHAR myW
[] = { 'M','y',0 };
114 static const WCHAR trustW
[] = { 'T','r','u','s','t',0 };
115 PCertificateChainEngine engine
=
116 CryptMemAlloc(sizeof(CertificateChainEngine
));
120 HCERTSTORE worldStores
[4];
123 engine
->hRoot
= root
;
124 engine
->hWorld
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
125 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
126 worldStores
[0] = CertDuplicateStore(engine
->hRoot
);
127 worldStores
[1] = CertOpenSystemStoreW(0, caW
);
128 worldStores
[2] = CertOpenSystemStoreW(0, myW
);
129 worldStores
[3] = CertOpenSystemStoreW(0, trustW
);
130 CRYPT_AddStoresToCollection(engine
->hWorld
,
131 sizeof(worldStores
) / sizeof(worldStores
[0]), worldStores
);
132 CRYPT_AddStoresToCollection(engine
->hWorld
,
133 pConfig
->cAdditionalStore
, pConfig
->rghAdditionalStore
);
134 CRYPT_CloseStores(sizeof(worldStores
) / sizeof(worldStores
[0]),
136 engine
->dwFlags
= pConfig
->dwFlags
;
137 engine
->dwUrlRetrievalTimeout
= pConfig
->dwUrlRetrievalTimeout
;
138 engine
->MaximumCachedCertificates
=
139 pConfig
->MaximumCachedCertificates
;
140 if (pConfig
->CycleDetectionModulus
)
141 engine
->CycleDetectionModulus
= pConfig
->CycleDetectionModulus
;
143 engine
->CycleDetectionModulus
= DEFAULT_CYCLE_MODULUS
;
145 return (HCERTCHAINENGINE
)engine
;
148 BOOL WINAPI
CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig
,
149 HCERTCHAINENGINE
*phChainEngine
)
153 TRACE("(%p, %p)\n", pConfig
, phChainEngine
);
155 if (pConfig
->cbSize
!= sizeof(*pConfig
))
157 SetLastError(E_INVALIDARG
);
160 *phChainEngine
= NULL
;
161 ret
= CRYPT_CheckRestrictedRoot(pConfig
->hRestrictedRoot
);
165 HCERTCHAINENGINE engine
;
167 if (pConfig
->hRestrictedRoot
)
168 root
= CertDuplicateStore(pConfig
->hRestrictedRoot
);
170 root
= CertOpenSystemStoreW(0, rootW
);
171 engine
= CRYPT_CreateChainEngine(root
, pConfig
);
174 *phChainEngine
= engine
;
183 VOID WINAPI
CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine
)
185 PCertificateChainEngine engine
= (PCertificateChainEngine
)hChainEngine
;
187 TRACE("(%p)\n", hChainEngine
);
189 if (engine
&& InterlockedDecrement(&engine
->ref
) == 0)
191 CertCloseStore(engine
->hWorld
, 0);
192 CertCloseStore(engine
->hRoot
, 0);
193 CryptMemFree(engine
);
197 static HCERTCHAINENGINE
CRYPT_GetDefaultChainEngine(void)
199 if (!CRYPT_defaultChainEngine
)
201 CERT_CHAIN_ENGINE_CONFIG config
= { 0 };
202 HCERTCHAINENGINE engine
;
204 config
.cbSize
= sizeof(config
);
205 CertCreateCertificateChainEngine(&config
, &engine
);
206 InterlockedCompareExchangePointer(&CRYPT_defaultChainEngine
, engine
,
208 if (CRYPT_defaultChainEngine
!= engine
)
209 CertFreeCertificateChainEngine(engine
);
211 return CRYPT_defaultChainEngine
;
214 void default_chain_engine_free(void)
216 CertFreeCertificateChainEngine(CRYPT_defaultChainEngine
);
219 typedef struct _CertificateChain
221 CERT_CHAIN_CONTEXT context
;
224 } CertificateChain
, *PCertificateChain
;
226 static inline BOOL
CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert
)
228 return CertCompareCertificateName(cert
->dwCertEncodingType
,
229 &cert
->pCertInfo
->Subject
, &cert
->pCertInfo
->Issuer
);
232 static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element
)
234 CertFreeCertificateContext(element
->pCertContext
);
235 CryptMemFree(element
);
238 static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain
)
240 DWORD i
, j
, cyclicCertIndex
= 0;
242 /* O(n^2) - I don't think there's a faster way */
243 for (i
= 0; !cyclicCertIndex
&& i
< chain
->cElement
; i
++)
244 for (j
= i
+ 1; !cyclicCertIndex
&& j
< chain
->cElement
; j
++)
245 if (CertCompareCertificate(X509_ASN_ENCODING
,
246 chain
->rgpElement
[i
]->pCertContext
->pCertInfo
,
247 chain
->rgpElement
[j
]->pCertContext
->pCertInfo
))
251 chain
->rgpElement
[cyclicCertIndex
]->TrustStatus
.dwErrorStatus
252 |= CERT_TRUST_IS_CYCLIC
;
253 /* Release remaining certs */
254 for (i
= cyclicCertIndex
+ 1; i
< chain
->cElement
; i
++)
255 CRYPT_FreeChainElement(chain
->rgpElement
[i
]);
257 chain
->cElement
= cyclicCertIndex
+ 1;
261 /* Checks whether the chain is cyclic by examining the last element's status */
262 static inline BOOL
CRYPT_IsSimpleChainCyclic(PCERT_SIMPLE_CHAIN chain
)
265 return chain
->rgpElement
[chain
->cElement
- 1]->TrustStatus
.dwErrorStatus
266 & CERT_TRUST_IS_CYCLIC
;
271 static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS
*chainStatus
,
272 CERT_TRUST_STATUS
*elementStatus
)
274 /* Any error that applies to an element also applies to a chain.. */
275 chainStatus
->dwErrorStatus
|= elementStatus
->dwErrorStatus
;
276 /* but the bottom nibble of an element's info status doesn't apply to the
279 chainStatus
->dwInfoStatus
|= (elementStatus
->dwInfoStatus
& 0xfffffff0);
282 static BOOL
CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine
,
283 PCERT_SIMPLE_CHAIN chain
, PCCERT_CONTEXT cert
, DWORD subjectInfoStatus
)
286 PCERT_CHAIN_ELEMENT element
= CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT
));
290 if (!chain
->cElement
)
291 chain
->rgpElement
= CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT
));
293 chain
->rgpElement
= CryptMemRealloc(chain
->rgpElement
,
294 (chain
->cElement
+ 1) * sizeof(PCERT_CHAIN_ELEMENT
));
295 if (chain
->rgpElement
)
297 chain
->rgpElement
[chain
->cElement
++] = element
;
298 memset(element
, 0, sizeof(CERT_CHAIN_ELEMENT
));
299 element
->cbSize
= sizeof(CERT_CHAIN_ELEMENT
);
300 element
->pCertContext
= CertDuplicateCertificateContext(cert
);
301 if (chain
->cElement
> 1)
302 chain
->rgpElement
[chain
->cElement
- 2]->TrustStatus
.dwInfoStatus
304 /* FIXME: initialize the rest of element */
305 if (chain
->cElement
% engine
->CycleDetectionModulus
)
306 CRYPT_CheckSimpleChainForCycles(chain
);
307 CRYPT_CombineTrustStatus(&chain
->TrustStatus
,
308 &element
->TrustStatus
);
312 CryptMemFree(element
);
317 static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain
)
321 for (i
= 0; i
< chain
->cElement
; i
++)
322 CRYPT_FreeChainElement(chain
->rgpElement
[i
]);
323 CryptMemFree(chain
->rgpElement
);
327 static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot
,
328 PCERT_CHAIN_ELEMENT rootElement
)
331 DWORD size
= sizeof(hash
);
332 CRYPT_HASH_BLOB blob
= { sizeof(hash
), hash
};
333 PCCERT_CONTEXT trustedRoot
;
335 CertGetCertificateContextProperty(rootElement
->pCertContext
,
336 CERT_HASH_PROP_ID
, hash
, &size
);
337 trustedRoot
= CertFindCertificateInStore(hRoot
,
338 rootElement
->pCertContext
->dwCertEncodingType
, 0, CERT_FIND_SHA1_HASH
,
341 rootElement
->TrustStatus
.dwErrorStatus
|=
342 CERT_TRUST_IS_UNTRUSTED_ROOT
;
344 CertFreeCertificateContext(trustedRoot
);
347 static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot
,
348 PCERT_CHAIN_ELEMENT rootElement
)
350 PCCERT_CONTEXT root
= rootElement
->pCertContext
;
352 if (!CryptVerifyCertificateSignatureEx(0, root
->dwCertEncodingType
,
353 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
, (void *)root
,
354 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
, (void *)root
, 0, NULL
))
356 TRACE("Last certificate's signature is invalid\n");
357 rootElement
->TrustStatus
.dwErrorStatus
|=
358 CERT_TRUST_IS_NOT_SIGNATURE_VALID
;
360 CRYPT_CheckTrustedStatus(hRoot
, rootElement
);
363 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
364 * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a
365 * CERT_BASIC_CONSTRAINTS2_INFO. If it neither extension is present, sets
366 * constraints->fCA to defaultIfNotSpecified.
367 * Returns FALSE if the extension is present but couldn't be decoded.
369 static BOOL
CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert
,
370 CERT_BASIC_CONSTRAINTS2_INFO
*constraints
, BOOL defaultIfNotSpecified
)
373 PCERT_EXTENSION ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS
,
374 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
376 constraints
->fPathLenConstraint
= FALSE
;
379 CERT_BASIC_CONSTRAINTS_INFO
*info
;
382 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
, szOID_BASIC_CONSTRAINTS
,
383 ext
->Value
.pbData
, ext
->Value
.cbData
, CRYPT_DECODE_ALLOC_FLAG
,
384 NULL
, (LPBYTE
)&info
, &size
);
387 if (info
->SubjectType
.cbData
== 1)
389 info
->SubjectType
.pbData
[0] & CERT_CA_SUBJECT_FLAG
;
395 ext
= CertFindExtension(szOID_BASIC_CONSTRAINTS2
,
396 cert
->pCertInfo
->cExtension
, cert
->pCertInfo
->rgExtension
);
399 DWORD size
= sizeof(CERT_BASIC_CONSTRAINTS2_INFO
);
401 ret
= CryptDecodeObjectEx(X509_ASN_ENCODING
,
402 szOID_BASIC_CONSTRAINTS2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
403 0, NULL
, constraints
, &size
);
406 constraints
->fCA
= defaultIfNotSpecified
;
411 /* Checks element's basic constraints to see if it can act as a CA, with
412 * remainingCAs CAs left in this chain. Updates chainConstraints with the
413 * element's constraints, if:
414 * 1. chainConstraints doesn't have a path length constraint, or
415 * 2. element's path length constraint is smaller than chainConstraints's
416 * Sets *pathLengthConstraintViolated to TRUE if a path length violation
418 * Returns TRUE if the element can be a CA, and the length of the remaining
421 static BOOL
CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert
,
422 CERT_BASIC_CONSTRAINTS2_INFO
*chainConstraints
, DWORD remainingCAs
,
423 BOOL
*pathLengthConstraintViolated
)
425 BOOL validBasicConstraints
;
426 CERT_BASIC_CONSTRAINTS2_INFO constraints
;
428 if ((validBasicConstraints
= CRYPT_DecodeBasicConstraints(cert
,
429 &constraints
, TRUE
)))
431 if (!constraints
.fCA
)
433 TRACE("chain element %d can't be a CA\n", remainingCAs
+ 1);
434 validBasicConstraints
= FALSE
;
436 else if (constraints
.fPathLenConstraint
)
438 /* If the element has path length constraints, they apply to the
439 * entire remaining chain.
441 if (!chainConstraints
->fPathLenConstraint
||
442 constraints
.dwPathLenConstraint
<
443 chainConstraints
->dwPathLenConstraint
)
445 TRACE("setting path length constraint to %d\n",
446 chainConstraints
->dwPathLenConstraint
);
447 chainConstraints
->fPathLenConstraint
= TRUE
;
448 chainConstraints
->dwPathLenConstraint
=
449 constraints
.dwPathLenConstraint
;
453 if (chainConstraints
->fPathLenConstraint
&&
454 remainingCAs
> chainConstraints
->dwPathLenConstraint
)
456 TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs
,
457 chainConstraints
->dwPathLenConstraint
);
458 validBasicConstraints
= FALSE
;
459 *pathLengthConstraintViolated
= TRUE
;
461 return validBasicConstraints
;
464 static BOOL
url_matches(LPCWSTR constraint
, LPCWSTR name
,
465 DWORD
*trustErrorStatus
)
469 TRACE("%s, %s\n", debugstr_w(constraint
), debugstr_w(name
));
472 *trustErrorStatus
|= CERT_TRUST_INVALID_NAME_CONSTRAINTS
;
475 else if (constraint
[0] == '.')
477 if (lstrlenW(name
) > lstrlenW(constraint
))
478 match
= !lstrcmpiW(name
+ lstrlenW(name
) - lstrlenW(constraint
),
482 match
= !lstrcmpiW(constraint
, name
);
486 static BOOL
rfc822_name_matches(LPCWSTR constraint
, LPCWSTR name
,
487 DWORD
*trustErrorStatus
)
492 TRACE("%s, %s\n", debugstr_w(constraint
), debugstr_w(name
));
495 *trustErrorStatus
|= CERT_TRUST_INVALID_NAME_CONSTRAINTS
;
498 else if ((at
= strchrW(constraint
, '@')))
499 match
= !lstrcmpiW(constraint
, name
);
502 if ((at
= strchrW(name
, '@')))
503 match
= url_matches(constraint
, at
+ 1, trustErrorStatus
);
505 match
= !lstrcmpiW(constraint
, name
);
510 static BOOL
dns_name_matches(LPCWSTR constraint
, LPCWSTR name
,
511 DWORD
*trustErrorStatus
)
515 TRACE("%s, %s\n", debugstr_w(constraint
), debugstr_w(name
));
518 *trustErrorStatus
|= CERT_TRUST_INVALID_NAME_CONSTRAINTS
;
521 else if (lstrlenW(name
) >= lstrlenW(constraint
))
522 match
= !lstrcmpiW(name
+ lstrlenW(name
) - lstrlenW(constraint
),
525 ; /* name is too short, no match */
529 static BOOL
ip_address_matches(const CRYPT_DATA_BLOB
*constraint
,
530 const CRYPT_DATA_BLOB
*name
, DWORD
*trustErrorStatus
)
534 TRACE("(%d, %p), (%d, %p)\n", constraint
->cbData
, constraint
->pbData
,
535 name
->cbData
, name
->pbData
);
537 if (constraint
->cbData
!= sizeof(DWORD
) * 2)
538 *trustErrorStatus
|= CERT_TRUST_INVALID_NAME_CONSTRAINTS
;
539 else if (name
->cbData
== sizeof(DWORD
))
541 DWORD subnet
, mask
, addr
;
543 memcpy(&subnet
, constraint
->pbData
, sizeof(subnet
));
544 memcpy(&mask
, constraint
->pbData
+ sizeof(subnet
), sizeof(mask
));
545 memcpy(&addr
, name
->pbData
, sizeof(addr
));
546 /* These are really in big-endian order, but for equality matching we
547 * don't need to swap to host order
549 match
= (subnet
& mask
) == (addr
& mask
);
552 ; /* name is wrong size, no match */
556 static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY
*constraint
,
557 const CERT_ALT_NAME_INFO
*subjectName
, DWORD
*trustErrorStatus
,
558 DWORD errorIfFound
, DWORD errorIfNotFound
)
561 BOOL defined
= FALSE
, match
= FALSE
;
563 for (i
= 0; i
< subjectName
->cAltEntry
; i
++)
565 if (subjectName
->rgAltEntry
[i
].dwAltNameChoice
==
566 constraint
->dwAltNameChoice
)
569 switch (constraint
->dwAltNameChoice
)
571 case CERT_ALT_NAME_RFC822_NAME
:
572 match
= rfc822_name_matches(constraint
->u
.pwszURL
,
573 subjectName
->rgAltEntry
[i
].u
.pwszURL
, trustErrorStatus
);
575 case CERT_ALT_NAME_DNS_NAME
:
576 match
= dns_name_matches(constraint
->u
.pwszURL
,
577 subjectName
->rgAltEntry
[i
].u
.pwszURL
, trustErrorStatus
);
579 case CERT_ALT_NAME_URL
:
580 match
= url_matches(constraint
->u
.pwszURL
,
581 subjectName
->rgAltEntry
[i
].u
.pwszURL
, trustErrorStatus
);
583 case CERT_ALT_NAME_IP_ADDRESS
:
584 match
= ip_address_matches(&constraint
->u
.IPAddress
,
585 &subjectName
->rgAltEntry
[i
].u
.IPAddress
, trustErrorStatus
);
587 case CERT_ALT_NAME_DIRECTORY_NAME
:
589 ERR("name choice %d unsupported in this context\n",
590 constraint
->dwAltNameChoice
);
592 CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT
;
596 /* Microsoft's implementation of name constraint checking appears at odds
598 * According to MSDN, CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT is set
599 * when a name constraint is present, but that name form is not defined in
600 * the end certificate. According to RFC 3280, "if no name of the type is
601 * in the certificate, the name is acceptable."
602 * I follow Microsoft here.
605 *trustErrorStatus
|= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
;
606 *trustErrorStatus
|= match
? errorIfFound
: errorIfNotFound
;
609 static void CRYPT_CheckNameConstraints(
610 const CERT_NAME_CONSTRAINTS_INFO
*nameConstraints
, const CERT_INFO
*cert
,
611 DWORD
*trustErrorStatus
)
613 /* If there aren't any existing constraints, don't bother checking */
614 if (nameConstraints
->cPermittedSubtree
|| nameConstraints
->cExcludedSubtree
)
618 if ((ext
= CertFindExtension(szOID_SUBJECT_ALT_NAME
, cert
->cExtension
,
621 CERT_ALT_NAME_INFO
*subjectName
;
624 if (CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_ALTERNATE_NAME
,
625 ext
->Value
.pbData
, ext
->Value
.cbData
,
626 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
627 &subjectName
, &size
))
631 for (i
= 0; i
< nameConstraints
->cExcludedSubtree
; i
++)
632 CRYPT_FindMatchingNameEntry(
633 &nameConstraints
->rgExcludedSubtree
[i
].Base
, subjectName
,
635 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
, 0);
636 for (i
= 0; i
< nameConstraints
->cPermittedSubtree
; i
++)
637 CRYPT_FindMatchingNameEntry(
638 &nameConstraints
->rgPermittedSubtree
[i
].Base
, subjectName
,
640 0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
);
641 LocalFree(subjectName
);
646 /* See above comment on CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT.
647 * I match Microsoft's implementation here as well.
649 *trustErrorStatus
|= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
;
650 if (nameConstraints
->cPermittedSubtree
)
652 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
;
653 if (nameConstraints
->cExcludedSubtree
)
655 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
;
660 /* Gets cert's name constraints, if any. Free with LocalFree. */
661 static CERT_NAME_CONSTRAINTS_INFO
*CRYPT_GetNameConstraints(CERT_INFO
*cert
)
663 CERT_NAME_CONSTRAINTS_INFO
*info
= NULL
;
667 if ((ext
= CertFindExtension(szOID_NAME_CONSTRAINTS
, cert
->cExtension
,
672 CryptDecodeObjectEx(X509_ASN_ENCODING
, X509_NAME_CONSTRAINTS
,
673 ext
->Value
.pbData
, ext
->Value
.cbData
,
674 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
, &info
,
680 static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain
)
684 /* Microsoft's implementation appears to violate RFC 3280: according to
685 * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's
686 * name constraint is violated in the end cert. According to RFC 3280,
687 * the constraints should be checked against every subsequent certificate
688 * in the chain, not just the end cert.
689 * Microsoft's implementation also sets the name constraint errors on the
690 * certs whose constraints were violated, not on the certs that violated
692 * In order to be error-compatible with Microsoft's implementation, while
693 * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name
696 for (i
= chain
->cElement
- 1; i
> 0; i
--)
698 CERT_NAME_CONSTRAINTS_INFO
*nameConstraints
;
700 if ((nameConstraints
= CRYPT_GetNameConstraints(
701 chain
->rgpElement
[i
]->pCertContext
->pCertInfo
)))
703 for (j
= i
- 1; j
>= 0; j
--)
705 DWORD errorStatus
= 0;
707 /* According to RFC 3280, self-signed certs don't have name
708 * constraints checked unless they're the end cert.
710 if (j
== 0 || !CRYPT_IsCertificateSelfSigned(
711 chain
->rgpElement
[j
]->pCertContext
))
713 CRYPT_CheckNameConstraints(nameConstraints
,
714 chain
->rgpElement
[i
]->pCertContext
->pCertInfo
,
716 chain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
|=
720 LocalFree(nameConstraints
);
725 static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine
,
726 PCERT_SIMPLE_CHAIN chain
, LPFILETIME time
)
728 PCERT_CHAIN_ELEMENT rootElement
= chain
->rgpElement
[chain
->cElement
- 1];
730 BOOL pathLengthConstraintViolated
= FALSE
;
731 CERT_BASIC_CONSTRAINTS2_INFO constraints
= { TRUE
, FALSE
, 0 };
733 for (i
= chain
->cElement
- 1; i
>= 0; i
--)
735 if (CertVerifyTimeValidity(time
,
736 chain
->rgpElement
[i
]->pCertContext
->pCertInfo
) != 0)
737 chain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
|=
738 CERT_TRUST_IS_NOT_TIME_VALID
;
741 /* Check the signature of the cert this issued */
742 if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING
,
743 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
,
744 (void *)chain
->rgpElement
[i
- 1]->pCertContext
,
745 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
,
746 (void *)chain
->rgpElement
[i
]->pCertContext
, 0, NULL
))
747 chain
->rgpElement
[i
- 1]->TrustStatus
.dwErrorStatus
|=
748 CERT_TRUST_IS_NOT_SIGNATURE_VALID
;
749 /* Once a path length constraint has been violated, every remaining
750 * CA cert's basic constraints is considered invalid.
752 if (pathLengthConstraintViolated
)
753 chain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
|=
754 CERT_TRUST_INVALID_BASIC_CONSTRAINTS
;
755 else if (!CRYPT_CheckBasicConstraintsForCA(
756 chain
->rgpElement
[i
]->pCertContext
, &constraints
, i
- 1,
757 &pathLengthConstraintViolated
))
758 chain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
|=
759 CERT_TRUST_INVALID_BASIC_CONSTRAINTS
;
760 else if (constraints
.fPathLenConstraint
&&
761 constraints
.dwPathLenConstraint
)
763 /* This one's valid - decrement max length */
764 constraints
.dwPathLenConstraint
--;
767 /* FIXME: check valid usages */
768 CRYPT_CombineTrustStatus(&chain
->TrustStatus
,
769 &chain
->rgpElement
[i
]->TrustStatus
);
771 CRYPT_CheckChainNameConstraints(chain
);
772 if (CRYPT_IsCertificateSelfSigned(rootElement
->pCertContext
))
774 rootElement
->TrustStatus
.dwInfoStatus
|=
775 CERT_TRUST_IS_SELF_SIGNED
| CERT_TRUST_HAS_NAME_MATCH_ISSUER
;
776 CRYPT_CheckRootCert(engine
->hRoot
, rootElement
);
778 /* FIXME: check revocation of every cert with CertVerifyRevocation */
779 CRYPT_CombineTrustStatus(&chain
->TrustStatus
, &rootElement
->TrustStatus
);
782 static PCCERT_CONTEXT
CRYPT_GetIssuer(HCERTSTORE store
, PCCERT_CONTEXT subject
,
783 PCCERT_CONTEXT prevIssuer
, DWORD
*infoStatus
)
785 PCCERT_CONTEXT issuer
= NULL
;
790 if ((ext
= CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER
,
791 subject
->pCertInfo
->cExtension
, subject
->pCertInfo
->rgExtension
)))
793 CERT_AUTHORITY_KEY_ID_INFO
*info
;
796 ret
= CryptDecodeObjectEx(subject
->dwCertEncodingType
,
797 X509_AUTHORITY_KEY_ID
, ext
->Value
.pbData
, ext
->Value
.cbData
,
798 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
804 if (info
->CertIssuer
.cbData
&& info
->CertSerialNumber
.cbData
)
806 id
.dwIdChoice
= CERT_ID_ISSUER_SERIAL_NUMBER
;
807 memcpy(&id
.u
.IssuerSerialNumber
.Issuer
, &info
->CertIssuer
,
808 sizeof(CERT_NAME_BLOB
));
809 memcpy(&id
.u
.IssuerSerialNumber
.SerialNumber
,
810 &info
->CertSerialNumber
, sizeof(CRYPT_INTEGER_BLOB
));
811 issuer
= CertFindCertificateInStore(store
,
812 subject
->dwCertEncodingType
, 0, CERT_FIND_CERT_ID
, &id
,
815 *infoStatus
= CERT_TRUST_HAS_EXACT_MATCH_ISSUER
;
817 else if (info
->KeyId
.cbData
)
819 id
.dwIdChoice
= CERT_ID_KEY_IDENTIFIER
;
820 memcpy(&id
.u
.KeyId
, &info
->KeyId
, sizeof(CRYPT_HASH_BLOB
));
821 issuer
= CertFindCertificateInStore(store
,
822 subject
->dwCertEncodingType
, 0, CERT_FIND_CERT_ID
, &id
,
825 *infoStatus
= CERT_TRUST_HAS_KEY_MATCH_ISSUER
;
830 else if ((ext
= CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2
,
831 subject
->pCertInfo
->cExtension
, subject
->pCertInfo
->rgExtension
)))
833 CERT_AUTHORITY_KEY_ID2_INFO
*info
;
836 ret
= CryptDecodeObjectEx(subject
->dwCertEncodingType
,
837 X509_AUTHORITY_KEY_ID2
, ext
->Value
.pbData
, ext
->Value
.cbData
,
838 CRYPT_DECODE_ALLOC_FLAG
| CRYPT_DECODE_NOCOPY_FLAG
, NULL
,
844 if (info
->AuthorityCertIssuer
.cAltEntry
&&
845 info
->AuthorityCertSerialNumber
.cbData
)
847 PCERT_ALT_NAME_ENTRY directoryName
= NULL
;
850 for (i
= 0; !directoryName
&&
851 i
< info
->AuthorityCertIssuer
.cAltEntry
; i
++)
852 if (info
->AuthorityCertIssuer
.rgAltEntry
[i
].dwAltNameChoice
853 == CERT_ALT_NAME_DIRECTORY_NAME
)
855 &info
->AuthorityCertIssuer
.rgAltEntry
[i
];
858 id
.dwIdChoice
= CERT_ID_ISSUER_SERIAL_NUMBER
;
859 memcpy(&id
.u
.IssuerSerialNumber
.Issuer
,
860 &directoryName
->u
.DirectoryName
, sizeof(CERT_NAME_BLOB
));
861 memcpy(&id
.u
.IssuerSerialNumber
.SerialNumber
,
862 &info
->AuthorityCertSerialNumber
,
863 sizeof(CRYPT_INTEGER_BLOB
));
864 issuer
= CertFindCertificateInStore(store
,
865 subject
->dwCertEncodingType
, 0, CERT_FIND_CERT_ID
, &id
,
868 *infoStatus
= CERT_TRUST_HAS_EXACT_MATCH_ISSUER
;
871 FIXME("no supported name type in authority key id2\n");
873 else if (info
->KeyId
.cbData
)
875 id
.dwIdChoice
= CERT_ID_KEY_IDENTIFIER
;
876 memcpy(&id
.u
.KeyId
, &info
->KeyId
, sizeof(CRYPT_HASH_BLOB
));
877 issuer
= CertFindCertificateInStore(store
,
878 subject
->dwCertEncodingType
, 0, CERT_FIND_CERT_ID
, &id
,
881 *infoStatus
= CERT_TRUST_HAS_KEY_MATCH_ISSUER
;
888 issuer
= CertFindCertificateInStore(store
,
889 subject
->dwCertEncodingType
, 0, CERT_FIND_SUBJECT_NAME
,
890 &subject
->pCertInfo
->Issuer
, prevIssuer
);
892 *infoStatus
= CERT_TRUST_HAS_NAME_MATCH_ISSUER
;
897 /* Builds a simple chain by finding an issuer for the last cert in the chain,
898 * until reaching a self-signed cert, or until no issuer can be found.
900 static BOOL
CRYPT_BuildSimpleChain(PCertificateChainEngine engine
,
901 HCERTSTORE world
, PCERT_SIMPLE_CHAIN chain
)
904 PCCERT_CONTEXT cert
= chain
->rgpElement
[chain
->cElement
- 1]->pCertContext
;
906 while (ret
&& !CRYPT_IsSimpleChainCyclic(chain
) &&
907 !CRYPT_IsCertificateSelfSigned(cert
))
910 PCCERT_CONTEXT issuer
= CRYPT_GetIssuer(world
, cert
, NULL
, &infoStatus
);
914 ret
= CRYPT_AddCertToSimpleChain(engine
, chain
, issuer
, infoStatus
);
919 TRACE("Couldn't find issuer, halting chain creation\n");
926 static BOOL
CRYPT_GetSimpleChainForCert(PCertificateChainEngine engine
,
927 HCERTSTORE world
, PCCERT_CONTEXT cert
, LPFILETIME pTime
,
928 PCERT_SIMPLE_CHAIN
*ppChain
)
931 PCERT_SIMPLE_CHAIN chain
;
933 TRACE("(%p, %p, %p, %p)\n", engine
, world
, cert
, pTime
);
935 chain
= CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN
));
938 memset(chain
, 0, sizeof(CERT_SIMPLE_CHAIN
));
939 chain
->cbSize
= sizeof(CERT_SIMPLE_CHAIN
);
940 ret
= CRYPT_AddCertToSimpleChain(engine
, chain
, cert
, 0);
943 ret
= CRYPT_BuildSimpleChain(engine
, world
, chain
);
945 CRYPT_CheckSimpleChain(engine
, chain
, pTime
);
949 CRYPT_FreeSimpleChain(chain
);
957 static BOOL
CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine
,
958 PCCERT_CONTEXT cert
, LPFILETIME pTime
, HCERTSTORE hAdditionalStore
,
959 PCertificateChain
*ppChain
)
961 PCertificateChainEngine engine
= (PCertificateChainEngine
)hChainEngine
;
962 PCERT_SIMPLE_CHAIN simpleChain
= NULL
;
966 world
= CertOpenStore(CERT_STORE_PROV_COLLECTION
, 0, 0,
967 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
968 CertAddStoreToCollection(world
, engine
->hWorld
, 0, 0);
969 if (hAdditionalStore
)
970 CertAddStoreToCollection(world
, hAdditionalStore
, 0, 0);
971 /* FIXME: only simple chains are supported for now, as CTLs aren't
974 if ((ret
= CRYPT_GetSimpleChainForCert(engine
, world
, cert
, pTime
,
977 PCertificateChain chain
= CryptMemAlloc(sizeof(CertificateChain
));
982 chain
->world
= world
;
983 chain
->context
.cbSize
= sizeof(CERT_CHAIN_CONTEXT
);
984 memcpy(&chain
->context
.TrustStatus
, &simpleChain
->TrustStatus
,
985 sizeof(CERT_TRUST_STATUS
));
986 chain
->context
.cChain
= 1;
987 chain
->context
.rgpChain
= CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN
));
988 chain
->context
.rgpChain
[0] = simpleChain
;
989 chain
->context
.cLowerQualityChainContext
= 0;
990 chain
->context
.rgpLowerQualityChainContext
= NULL
;
991 chain
->context
.fHasRevocationFreshnessTime
= FALSE
;
992 chain
->context
.dwRevocationFreshnessTime
= 0;
1001 /* Makes and returns a copy of chain, up to and including element iElement. */
1002 static PCERT_SIMPLE_CHAIN
CRYPT_CopySimpleChainToElement(
1003 PCERT_SIMPLE_CHAIN chain
, DWORD iElement
)
1005 PCERT_SIMPLE_CHAIN copy
= CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN
));
1009 memset(copy
, 0, sizeof(CERT_SIMPLE_CHAIN
));
1010 copy
->cbSize
= sizeof(CERT_SIMPLE_CHAIN
);
1012 CryptMemAlloc((iElement
+ 1) * sizeof(PCERT_CHAIN_ELEMENT
));
1013 if (copy
->rgpElement
)
1018 memset(copy
->rgpElement
, 0,
1019 (iElement
+ 1) * sizeof(PCERT_CHAIN_ELEMENT
));
1020 for (i
= 0; ret
&& i
<= iElement
; i
++)
1022 PCERT_CHAIN_ELEMENT element
=
1023 CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT
));
1027 memcpy(element
, chain
->rgpElement
[i
],
1028 sizeof(CERT_CHAIN_ELEMENT
));
1029 element
->pCertContext
= CertDuplicateCertificateContext(
1030 chain
->rgpElement
[i
]->pCertContext
);
1031 /* Reset the trust status of the copied element, it'll get
1032 * rechecked after the new chain is done.
1034 memset(&element
->TrustStatus
, 0, sizeof(CERT_TRUST_STATUS
));
1035 copy
->rgpElement
[copy
->cElement
++] = element
;
1042 for (i
= 0; i
<= iElement
; i
++)
1043 CryptMemFree(copy
->rgpElement
[i
]);
1044 CryptMemFree(copy
->rgpElement
);
1058 static void CRYPT_FreeLowerQualityChains(PCertificateChain chain
)
1062 for (i
= 0; i
< chain
->context
.cLowerQualityChainContext
; i
++)
1063 CertFreeCertificateChain(chain
->context
.rgpLowerQualityChainContext
[i
]);
1064 CryptMemFree(chain
->context
.rgpLowerQualityChainContext
);
1065 chain
->context
.cLowerQualityChainContext
= 0;
1066 chain
->context
.rgpLowerQualityChainContext
= NULL
;
1069 static void CRYPT_FreeChainContext(PCertificateChain chain
)
1073 CRYPT_FreeLowerQualityChains(chain
);
1074 for (i
= 0; i
< chain
->context
.cChain
; i
++)
1075 CRYPT_FreeSimpleChain(chain
->context
.rgpChain
[i
]);
1076 CryptMemFree(chain
->context
.rgpChain
);
1077 CertCloseStore(chain
->world
, 0);
1078 CryptMemFree(chain
);
1081 /* Makes and returns a copy of chain, up to and including element iElement of
1082 * simple chain iChain.
1084 static PCertificateChain
CRYPT_CopyChainToElement(PCertificateChain chain
,
1085 DWORD iChain
, DWORD iElement
)
1087 PCertificateChain copy
= CryptMemAlloc(sizeof(CertificateChain
));
1092 copy
->world
= CertDuplicateStore(chain
->world
);
1093 copy
->context
.cbSize
= sizeof(CERT_CHAIN_CONTEXT
);
1094 /* Leave the trust status of the copied chain unset, it'll get
1095 * rechecked after the new chain is done.
1097 memset(©
->context
.TrustStatus
, 0, sizeof(CERT_TRUST_STATUS
));
1098 copy
->context
.cLowerQualityChainContext
= 0;
1099 copy
->context
.rgpLowerQualityChainContext
= NULL
;
1100 copy
->context
.fHasRevocationFreshnessTime
= FALSE
;
1101 copy
->context
.dwRevocationFreshnessTime
= 0;
1102 copy
->context
.rgpChain
= CryptMemAlloc(
1103 (iChain
+ 1) * sizeof(PCERT_SIMPLE_CHAIN
));
1104 if (copy
->context
.rgpChain
)
1109 memset(copy
->context
.rgpChain
, 0,
1110 (iChain
+ 1) * sizeof(PCERT_SIMPLE_CHAIN
));
1113 for (i
= 0; ret
&& iChain
&& i
< iChain
- 1; i
++)
1115 copy
->context
.rgpChain
[i
] =
1116 CRYPT_CopySimpleChainToElement(chain
->context
.rgpChain
[i
],
1117 chain
->context
.rgpChain
[i
]->cElement
- 1);
1118 if (!copy
->context
.rgpChain
[i
])
1126 copy
->context
.rgpChain
[i
] =
1127 CRYPT_CopySimpleChainToElement(chain
->context
.rgpChain
[i
],
1129 if (!copy
->context
.rgpChain
[i
])
1134 CRYPT_FreeChainContext(copy
);
1138 copy
->context
.cChain
= iChain
+ 1;
1149 static PCertificateChain
CRYPT_BuildAlternateContextFromChain(
1150 HCERTCHAINENGINE hChainEngine
, LPFILETIME pTime
, HCERTSTORE hAdditionalStore
,
1151 PCertificateChain chain
)
1153 PCertificateChainEngine engine
= (PCertificateChainEngine
)hChainEngine
;
1154 PCertificateChain alternate
;
1156 TRACE("(%p, %p, %p, %p)\n", hChainEngine
, pTime
, hAdditionalStore
, chain
);
1158 /* Always start with the last "lower quality" chain to ensure a consistent
1159 * order of alternate creation:
1161 if (chain
->context
.cLowerQualityChainContext
)
1162 chain
= (PCertificateChain
)chain
->context
.rgpLowerQualityChainContext
[
1163 chain
->context
.cLowerQualityChainContext
- 1];
1164 /* A chain with only one element can't have any alternates */
1165 if (chain
->context
.cChain
<= 1 && chain
->context
.rgpChain
[0]->cElement
<= 1)
1169 DWORD i
, j
, infoStatus
;
1170 PCCERT_CONTEXT alternateIssuer
= NULL
;
1173 for (i
= 0; !alternateIssuer
&& i
< chain
->context
.cChain
; i
++)
1174 for (j
= 0; !alternateIssuer
&&
1175 j
< chain
->context
.rgpChain
[i
]->cElement
- 1; j
++)
1177 PCCERT_CONTEXT subject
=
1178 chain
->context
.rgpChain
[i
]->rgpElement
[j
]->pCertContext
;
1179 PCCERT_CONTEXT prevIssuer
= CertDuplicateCertificateContext(
1180 chain
->context
.rgpChain
[i
]->rgpElement
[j
+ 1]->pCertContext
);
1182 alternateIssuer
= CRYPT_GetIssuer(prevIssuer
->hCertStore
,
1183 subject
, prevIssuer
, &infoStatus
);
1185 if (alternateIssuer
)
1189 alternate
= CRYPT_CopyChainToElement(chain
, i
, j
);
1192 BOOL ret
= CRYPT_AddCertToSimpleChain(engine
,
1193 alternate
->context
.rgpChain
[i
], alternateIssuer
, infoStatus
);
1197 ret
= CRYPT_BuildSimpleChain(engine
, alternate
->world
,
1198 alternate
->context
.rgpChain
[i
]);
1200 CRYPT_CheckSimpleChain(engine
,
1201 alternate
->context
.rgpChain
[i
], pTime
);
1202 CRYPT_CombineTrustStatus(&alternate
->context
.TrustStatus
,
1203 &alternate
->context
.rgpChain
[i
]->TrustStatus
);
1207 CRYPT_FreeChainContext(alternate
);
1213 TRACE("%p\n", alternate
);
1217 #define CHAIN_QUALITY_SIGNATURE_VALID 8
1218 #define CHAIN_QUALITY_TIME_VALID 4
1219 #define CHAIN_QUALITY_COMPLETE_CHAIN 2
1220 #define CHAIN_QUALITY_TRUSTED_ROOT 1
1222 #define CHAIN_QUALITY_HIGHEST \
1223 CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
1224 CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT
1226 #define IS_TRUST_ERROR_SET(TrustStatus, bits) \
1227 (TrustStatus)->dwErrorStatus & (bits)
1229 static DWORD
CRYPT_ChainQuality(PCertificateChain chain
)
1231 DWORD quality
= CHAIN_QUALITY_HIGHEST
;
1233 if (IS_TRUST_ERROR_SET(&chain
->context
.TrustStatus
,
1234 CERT_TRUST_IS_UNTRUSTED_ROOT
))
1235 quality
&= ~CHAIN_QUALITY_TRUSTED_ROOT
;
1236 if (IS_TRUST_ERROR_SET(&chain
->context
.TrustStatus
,
1237 CERT_TRUST_IS_PARTIAL_CHAIN
))
1238 if (chain
->context
.TrustStatus
.dwErrorStatus
& CERT_TRUST_IS_PARTIAL_CHAIN
)
1239 quality
&= ~CHAIN_QUALITY_COMPLETE_CHAIN
;
1240 if (IS_TRUST_ERROR_SET(&chain
->context
.TrustStatus
,
1241 CERT_TRUST_IS_NOT_TIME_VALID
| CERT_TRUST_IS_NOT_TIME_NESTED
))
1242 quality
&= ~CHAIN_QUALITY_TIME_VALID
;
1243 if (IS_TRUST_ERROR_SET(&chain
->context
.TrustStatus
,
1244 CERT_TRUST_IS_NOT_SIGNATURE_VALID
))
1245 quality
&= ~CHAIN_QUALITY_SIGNATURE_VALID
;
1249 /* Chooses the highest quality chain among chain and its "lower quality"
1250 * alternate chains. Returns the highest quality chain, with all other
1251 * chains as lower quality chains of it.
1253 static PCertificateChain
CRYPT_ChooseHighestQualityChain(
1254 PCertificateChain chain
)
1258 /* There are always only two chains being considered: chain, and an
1259 * alternate at chain->rgpLowerQualityChainContext[i]. If the alternate
1260 * has a higher quality than chain, the alternate gets assigned the lower
1261 * quality contexts, with chain taking the alternate's place among the
1262 * lower quality contexts.
1264 for (i
= 0; i
< chain
->context
.cLowerQualityChainContext
; i
++)
1266 PCertificateChain alternate
=
1267 (PCertificateChain
)chain
->context
.rgpLowerQualityChainContext
[i
];
1269 if (CRYPT_ChainQuality(alternate
) > CRYPT_ChainQuality(chain
))
1271 alternate
->context
.cLowerQualityChainContext
=
1272 chain
->context
.cLowerQualityChainContext
;
1273 alternate
->context
.rgpLowerQualityChainContext
=
1274 chain
->context
.rgpLowerQualityChainContext
;
1275 alternate
->context
.rgpLowerQualityChainContext
[i
] =
1276 (PCCERT_CHAIN_CONTEXT
)chain
;
1277 chain
->context
.cLowerQualityChainContext
= 0;
1278 chain
->context
.rgpLowerQualityChainContext
= NULL
;
1285 static BOOL
CRYPT_AddAlternateChainToChain(PCertificateChain chain
,
1286 PCertificateChain alternate
)
1290 if (chain
->context
.cLowerQualityChainContext
)
1291 chain
->context
.rgpLowerQualityChainContext
=
1292 CryptMemRealloc(chain
->context
.rgpLowerQualityChainContext
,
1293 (chain
->context
.cLowerQualityChainContext
+ 1) *
1294 sizeof(PCCERT_CHAIN_CONTEXT
));
1296 chain
->context
.rgpLowerQualityChainContext
=
1297 CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT
));
1298 if (chain
->context
.rgpLowerQualityChainContext
)
1300 chain
->context
.rgpLowerQualityChainContext
[
1301 chain
->context
.cLowerQualityChainContext
++] =
1302 (PCCERT_CHAIN_CONTEXT
)alternate
;
1310 typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS
{
1312 CERT_USAGE_MATCH RequestedUsage
;
1313 } CERT_CHAIN_PARA_NO_EXTRA_FIELDS
, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS
;
1315 typedef struct _CERT_CHAIN_PARA_EXTRA_FIELDS
{
1317 CERT_USAGE_MATCH RequestedUsage
;
1318 CERT_USAGE_MATCH RequestedIssuancePolicy
;
1319 DWORD dwUrlRetrievalTimeout
;
1320 BOOL fCheckRevocationFreshnessTime
;
1321 DWORD dwRevocationFreshnessTime
;
1322 } CERT_CHAIN_PARA_EXTRA_FIELDS
, *PCERT_CHAIN_PARA_EXTRA_FIELDS
;
1324 BOOL WINAPI
CertGetCertificateChain(HCERTCHAINENGINE hChainEngine
,
1325 PCCERT_CONTEXT pCertContext
, LPFILETIME pTime
, HCERTSTORE hAdditionalStore
,
1326 PCERT_CHAIN_PARA pChainPara
, DWORD dwFlags
, LPVOID pvReserved
,
1327 PCCERT_CHAIN_CONTEXT
* ppChainContext
)
1330 PCertificateChain chain
= NULL
;
1332 TRACE("(%p, %p, %p, %p, %p, %08x, %p, %p)\n", hChainEngine
, pCertContext
,
1333 pTime
, hAdditionalStore
, pChainPara
, dwFlags
, pvReserved
, ppChainContext
);
1336 *ppChainContext
= NULL
;
1339 SetLastError(E_INVALIDARG
);
1342 if (!pCertContext
->pCertInfo
->SignatureAlgorithm
.pszObjId
)
1344 SetLastError(ERROR_INVALID_DATA
);
1348 hChainEngine
= CRYPT_GetDefaultChainEngine();
1349 /* FIXME: what about HCCE_LOCAL_MACHINE? */
1350 /* FIXME: pChainPara is for now ignored */
1351 ret
= CRYPT_BuildCandidateChainFromCert(hChainEngine
, pCertContext
, pTime
,
1352 hAdditionalStore
, &chain
);
1355 PCertificateChain alternate
= NULL
;
1358 alternate
= CRYPT_BuildAlternateContextFromChain(hChainEngine
,
1359 pTime
, hAdditionalStore
, chain
);
1361 /* Alternate contexts are added as "lower quality" contexts of
1362 * chain, to avoid loops in alternate chain creation.
1363 * The highest-quality chain is chosen at the end.
1366 ret
= CRYPT_AddAlternateChainToChain(chain
, alternate
);
1367 } while (ret
&& alternate
);
1368 chain
= CRYPT_ChooseHighestQualityChain(chain
);
1369 if (!(dwFlags
& CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS
))
1370 CRYPT_FreeLowerQualityChains(chain
);
1372 *ppChainContext
= (PCCERT_CHAIN_CONTEXT
)chain
;
1374 CertFreeCertificateChain((PCCERT_CHAIN_CONTEXT
)chain
);
1376 TRACE("returning %d\n", ret
);
1380 PCCERT_CHAIN_CONTEXT WINAPI
CertDuplicateCertificateChain(
1381 PCCERT_CHAIN_CONTEXT pChainContext
)
1383 PCertificateChain chain
= (PCertificateChain
)pChainContext
;
1385 TRACE("(%p)\n", pChainContext
);
1388 InterlockedIncrement(&chain
->ref
);
1389 return pChainContext
;
1392 VOID WINAPI
CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext
)
1394 PCertificateChain chain
= (PCertificateChain
)pChainContext
;
1396 TRACE("(%p)\n", pChainContext
);
1400 if (InterlockedDecrement(&chain
->ref
) == 0)
1401 CRYPT_FreeChainContext(chain
);
1405 static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain
, DWORD error
,
1406 LONG
*iChain
, LONG
*iElement
)
1410 for (i
= 0; i
< chain
->cChain
; i
++)
1411 for (j
= 0; j
< chain
->rgpChain
[i
]->cElement
; j
++)
1412 if (chain
->rgpChain
[i
]->rgpElement
[j
]->TrustStatus
.dwErrorStatus
&
1421 static BOOL WINAPI
verify_base_policy(LPCSTR szPolicyOID
,
1422 PCCERT_CHAIN_CONTEXT pChainContext
, PCERT_CHAIN_POLICY_PARA pPolicyPara
,
1423 PCERT_CHAIN_POLICY_STATUS pPolicyStatus
)
1425 pPolicyStatus
->lChainIndex
= pPolicyStatus
->lElementIndex
= -1;
1426 if (pChainContext
->TrustStatus
.dwErrorStatus
&
1427 CERT_TRUST_IS_NOT_SIGNATURE_VALID
)
1429 pPolicyStatus
->dwError
= TRUST_E_CERT_SIGNATURE
;
1430 find_element_with_error(pChainContext
,
1431 CERT_TRUST_IS_NOT_SIGNATURE_VALID
, &pPolicyStatus
->lChainIndex
,
1432 &pPolicyStatus
->lElementIndex
);
1434 else if (pChainContext
->TrustStatus
.dwErrorStatus
&
1435 CERT_TRUST_IS_UNTRUSTED_ROOT
)
1437 pPolicyStatus
->dwError
= CERT_E_UNTRUSTEDROOT
;
1438 find_element_with_error(pChainContext
,
1439 CERT_TRUST_IS_UNTRUSTED_ROOT
, &pPolicyStatus
->lChainIndex
,
1440 &pPolicyStatus
->lElementIndex
);
1442 else if (pChainContext
->TrustStatus
.dwErrorStatus
& CERT_TRUST_IS_CYCLIC
)
1444 pPolicyStatus
->dwError
= CERT_E_CHAINING
;
1445 find_element_with_error(pChainContext
, CERT_TRUST_IS_CYCLIC
,
1446 &pPolicyStatus
->lChainIndex
, &pPolicyStatus
->lElementIndex
);
1447 /* For a cyclic chain, which element is a cycle isn't meaningful */
1448 pPolicyStatus
->lElementIndex
= -1;
1451 pPolicyStatus
->dwError
= NO_ERROR
;
1455 static BYTE msTestPubKey1
[] = {
1456 0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9,
1457 0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7,
1458 0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f,
1459 0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10,
1460 0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
1461 static BYTE msTestPubKey2
[] = {
1462 0x30,0x48,0x02,0x41,0x00,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,
1463 0xd9,0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,
1464 0xf7,0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,
1465 0x5f,0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,
1466 0x10,0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
1467 static BYTE msTestPubKey3
[] = {
1468 0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5,
1469 0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8,
1470 0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6,
1471 0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18,
1472 0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 };
1474 static BOOL WINAPI
verify_authenticode_policy(LPCSTR szPolicyOID
,
1475 PCCERT_CHAIN_CONTEXT pChainContext
, PCERT_CHAIN_POLICY_PARA pPolicyPara
,
1476 PCERT_CHAIN_POLICY_STATUS pPolicyStatus
)
1478 BOOL ret
= verify_base_policy(szPolicyOID
, pChainContext
, pPolicyPara
,
1481 if (ret
&& pPolicyStatus
->dwError
== CERT_E_UNTRUSTEDROOT
)
1483 CERT_PUBLIC_KEY_INFO msPubKey
= { { 0 } };
1484 BOOL isMSTestRoot
= FALSE
;
1485 PCCERT_CONTEXT failingCert
=
1486 pChainContext
->rgpChain
[pPolicyStatus
->lChainIndex
]->
1487 rgpElement
[pPolicyStatus
->lElementIndex
]->pCertContext
;
1489 CRYPT_DATA_BLOB keyBlobs
[] = {
1490 { sizeof(msTestPubKey1
), msTestPubKey1
},
1491 { sizeof(msTestPubKey2
), msTestPubKey2
},
1492 { sizeof(msTestPubKey3
), msTestPubKey3
},
1495 /* Check whether the root is an MS test root */
1496 for (i
= 0; !isMSTestRoot
&& i
< sizeof(keyBlobs
) / sizeof(keyBlobs
[0]);
1499 msPubKey
.PublicKey
.cbData
= keyBlobs
[i
].cbData
;
1500 msPubKey
.PublicKey
.pbData
= keyBlobs
[i
].pbData
;
1501 if (CertComparePublicKeyInfo(
1502 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
1503 &failingCert
->pCertInfo
->SubjectPublicKeyInfo
, &msPubKey
))
1504 isMSTestRoot
= TRUE
;
1507 pPolicyStatus
->dwError
= CERT_E_UNTRUSTEDTESTROOT
;
1512 static BOOL WINAPI
verify_basic_constraints_policy(LPCSTR szPolicyOID
,
1513 PCCERT_CHAIN_CONTEXT pChainContext
, PCERT_CHAIN_POLICY_PARA pPolicyPara
,
1514 PCERT_CHAIN_POLICY_STATUS pPolicyStatus
)
1516 pPolicyStatus
->lChainIndex
= pPolicyStatus
->lElementIndex
= -1;
1517 if (pChainContext
->TrustStatus
.dwErrorStatus
&
1518 CERT_TRUST_INVALID_BASIC_CONSTRAINTS
)
1520 pPolicyStatus
->dwError
= TRUST_E_BASIC_CONSTRAINTS
;
1521 find_element_with_error(pChainContext
,
1522 CERT_TRUST_INVALID_BASIC_CONSTRAINTS
, &pPolicyStatus
->lChainIndex
,
1523 &pPolicyStatus
->lElementIndex
);
1526 pPolicyStatus
->dwError
= NO_ERROR
;
1530 static BYTE msPubKey1
[] = {
1531 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
1532 0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
1533 0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29,
1534 0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16,
1535 0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60,
1536 0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5,
1537 0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d,
1538 0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61,
1539 0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e,
1540 0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94,
1541 0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb,
1542 0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a,
1543 0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d,
1544 0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb,
1545 0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08,
1546 0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43,
1547 0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf,
1548 0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 };
1549 static BYTE msPubKey2
[] = {
1550 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6,
1551 0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25,
1552 0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2,
1553 0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54,
1554 0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62,
1555 0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a,
1556 0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7,
1557 0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84,
1558 0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9,
1559 0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91,
1560 0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52,
1561 0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80,
1562 0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18,
1563 0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07,
1564 0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef,
1565 0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0,
1566 0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30,
1567 0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 };
1568 static BYTE msPubKey3
[] = {
1569 0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4,
1570 0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7,
1571 0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94,
1572 0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04,
1573 0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d,
1574 0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09,
1575 0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae,
1576 0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7,
1577 0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f,
1578 0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94,
1579 0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d,
1580 0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05,
1581 0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e,
1582 0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d,
1583 0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b,
1584 0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67,
1585 0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08,
1586 0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5,
1587 0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64,
1588 0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38,
1589 0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0,
1590 0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9,
1591 0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28,
1592 0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc,
1593 0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45,
1594 0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde,
1595 0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04,
1596 0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89,
1597 0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11,
1598 0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32,
1599 0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40,
1600 0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41,
1601 0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1,
1602 0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5,
1603 0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00,
1606 static BOOL WINAPI
verify_ms_root_policy(LPCSTR szPolicyOID
,
1607 PCCERT_CHAIN_CONTEXT pChainContext
, PCERT_CHAIN_POLICY_PARA pPolicyPara
,
1608 PCERT_CHAIN_POLICY_STATUS pPolicyStatus
)
1610 BOOL ret
= verify_base_policy(szPolicyOID
, pChainContext
, pPolicyPara
,
1613 if (ret
&& !pPolicyStatus
->dwError
)
1615 CERT_PUBLIC_KEY_INFO msPubKey
= { { 0 } };
1616 BOOL isMSRoot
= FALSE
;
1618 CRYPT_DATA_BLOB keyBlobs
[] = {
1619 { sizeof(msPubKey1
), msPubKey1
},
1620 { sizeof(msPubKey2
), msPubKey2
},
1621 { sizeof(msPubKey3
), msPubKey3
},
1623 PCERT_SIMPLE_CHAIN rootChain
=
1624 pChainContext
->rgpChain
[pChainContext
->cChain
-1 ];
1625 PCCERT_CONTEXT root
=
1626 rootChain
->rgpElement
[rootChain
->cElement
- 1]->pCertContext
;
1628 for (i
= 0; !isMSRoot
&& i
< sizeof(keyBlobs
) / sizeof(keyBlobs
[0]);
1631 msPubKey
.PublicKey
.cbData
= keyBlobs
[i
].cbData
;
1632 msPubKey
.PublicKey
.pbData
= keyBlobs
[i
].pbData
;
1633 if (CertComparePublicKeyInfo(
1634 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
1635 &root
->pCertInfo
->SubjectPublicKeyInfo
, &msPubKey
))
1639 pPolicyStatus
->lChainIndex
= pPolicyStatus
->lElementIndex
= 0;
1644 typedef BOOL (WINAPI
*CertVerifyCertificateChainPolicyFunc
)(LPCSTR szPolicyOID
,
1645 PCCERT_CHAIN_CONTEXT pChainContext
, PCERT_CHAIN_POLICY_PARA pPolicyPara
,
1646 PCERT_CHAIN_POLICY_STATUS pPolicyStatus
);
1648 BOOL WINAPI
CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID
,
1649 PCCERT_CHAIN_CONTEXT pChainContext
, PCERT_CHAIN_POLICY_PARA pPolicyPara
,
1650 PCERT_CHAIN_POLICY_STATUS pPolicyStatus
)
1652 static HCRYPTOIDFUNCSET set
= NULL
;
1654 CertVerifyCertificateChainPolicyFunc verifyPolicy
= NULL
;
1655 HCRYPTOIDFUNCADDR hFunc
= NULL
;
1657 TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID
), pChainContext
,
1658 pPolicyPara
, pPolicyStatus
);
1660 if (!HIWORD(szPolicyOID
))
1662 switch (LOWORD(szPolicyOID
))
1664 case (int)CERT_CHAIN_POLICY_BASE
:
1665 verifyPolicy
= verify_base_policy
;
1667 case (int)CERT_CHAIN_POLICY_AUTHENTICODE
:
1668 verifyPolicy
= verify_authenticode_policy
;
1670 case (int)CERT_CHAIN_POLICY_BASIC_CONSTRAINTS
:
1671 verifyPolicy
= verify_basic_constraints_policy
;
1673 case (int)CERT_CHAIN_POLICY_MICROSOFT_ROOT
:
1674 verifyPolicy
= verify_ms_root_policy
;
1677 FIXME("unimplemented for %d\n", LOWORD(szPolicyOID
));
1683 set
= CryptInitOIDFunctionSet(
1684 CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC
, 0);
1685 CryptGetOIDFunctionAddress(set
, X509_ASN_ENCODING
, szPolicyOID
, 0,
1686 (void **)&verifyPolicy
, hFunc
);
1689 ret
= verifyPolicy(szPolicyOID
, pChainContext
, pPolicyPara
,
1692 CryptFreeOIDFunctionAddress(hFunc
, 0);