xref: /reactos/dll/win32/crypt32/chain.c (revision 5ddbd373)
1 /*
2  * Copyright 2006 Juan Lang
3  *
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.
8  *
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.
13  *
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
17  *
18  */
19 #include <stdarg.h>
20 #define NONAMELESSUNION
21 #include "windef.h"
22 #include "winbase.h"
23 #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
24 #define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
25 #include "wincrypt.h"
26 #include "wininet.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
29 #include "crypt32_private.h"
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 WINE_DECLARE_DEBUG_CHANNEL(chain);
33 
34 #define DEFAULT_CYCLE_MODULUS 7
35 
36 /* This represents a subset of a certificate chain engine:  it doesn't include
37  * the "hOther" store described by MSDN, because I'm not sure how that's used.
38  * It also doesn't include the "hTrust" store, because I don't yet implement
39  * CTLs or complex certificate chains.
40  */
41 typedef struct _CertificateChainEngine
42 {
43     LONG       ref;
44     HCERTSTORE hRoot;
45     HCERTSTORE hWorld;
46     DWORD      dwFlags;
47     DWORD      dwUrlRetrievalTimeout;
48     DWORD      MaximumCachedCertificates;
49     DWORD      CycleDetectionModulus;
50 } CertificateChainEngine;
51 
52 static inline void CRYPT_AddStoresToCollection(HCERTSTORE collection,
53  DWORD cStores, HCERTSTORE *stores)
54 {
55     DWORD i;
56 
57     for (i = 0; i < cStores; i++)
58         CertAddStoreToCollection(collection, stores[i], 0, 0);
59 }
60 
61 static inline void CRYPT_CloseStores(DWORD cStores, HCERTSTORE *stores)
62 {
63     DWORD i;
64 
65     for (i = 0; i < cStores; i++)
66         CertCloseStore(stores[i], 0);
67 }
68 
69 static const WCHAR rootW[] = { 'R','o','o','t',0 };
70 
71 /* Finds cert in store by comparing the cert's hashes. */
72 static PCCERT_CONTEXT CRYPT_FindCertInStore(HCERTSTORE store,
73  PCCERT_CONTEXT cert)
74 {
75     PCCERT_CONTEXT matching = NULL;
76     BYTE hash[20];
77     DWORD size = sizeof(hash);
78 
79     if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, hash, &size))
80     {
81         CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
82 
83         matching = CertFindCertificateInStore(store, cert->dwCertEncodingType,
84          0, CERT_FIND_SHA1_HASH, &blob, NULL);
85     }
86     return matching;
87 }
88 
89 static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store)
90 {
91     BOOL ret = TRUE;
92 
93     if (store)
94     {
95         HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW);
96         PCCERT_CONTEXT cert = NULL, check;
97 
98         do {
99             cert = CertEnumCertificatesInStore(store, cert);
100             if (cert)
101             {
102                 if (!(check = CRYPT_FindCertInStore(rootStore, cert)))
103                     ret = FALSE;
104                 else
105                     CertFreeCertificateContext(check);
106             }
107         } while (ret && cert);
108         if (cert)
109             CertFreeCertificateContext(cert);
110         CertCloseStore(rootStore, 0);
111     }
112     return ret;
113 }
114 
115 HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root, DWORD system_store, const CERT_CHAIN_ENGINE_CONFIG *config)
116 {
117     CertificateChainEngine *engine;
118     HCERTSTORE worldStores[4];
119 
120     static const WCHAR caW[] = { 'C','A',0 };
121     static const WCHAR myW[] = { 'M','y',0 };
122     static const WCHAR trustW[] = { 'T','r','u','s','t',0 };
123 
124     if(!root) {
125         if(config->cbSize >= sizeof(CERT_CHAIN_ENGINE_CONFIG) && config->hExclusiveRoot)
126             root = CertDuplicateStore(config->hExclusiveRoot);
127         else if (config->hRestrictedRoot)
128             root = CertDuplicateStore(config->hRestrictedRoot);
129         else
130             root = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, rootW);
131         if(!root)
132             return NULL;
133     }
134 
135     engine = CryptMemAlloc(sizeof(CertificateChainEngine));
136     if(!engine) {
137         CertCloseStore(root, 0);
138         return NULL;
139     }
140 
141     engine->ref = 1;
142     engine->hRoot = root;
143     engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
144     worldStores[0] = CertDuplicateStore(engine->hRoot);
145     worldStores[1] = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, caW);
146     worldStores[2] = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, myW);
147     worldStores[3] = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0, system_store, trustW);
148 
149     CRYPT_AddStoresToCollection(engine->hWorld,  sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
150     CRYPT_AddStoresToCollection(engine->hWorld,  config->cAdditionalStore, config->rghAdditionalStore);
151     CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
152 
153     engine->dwFlags = config->dwFlags;
154     engine->dwUrlRetrievalTimeout = config->dwUrlRetrievalTimeout;
155     engine->MaximumCachedCertificates = config->MaximumCachedCertificates;
156     if(config->CycleDetectionModulus)
157         engine->CycleDetectionModulus = config->CycleDetectionModulus;
158     else
159         engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS;
160 
161     return engine;
162 }
163 
164 static CertificateChainEngine *default_cu_engine, *default_lm_engine;
165 
166 static CertificateChainEngine *get_chain_engine(HCERTCHAINENGINE handle, BOOL allow_default)
167 {
168     const CERT_CHAIN_ENGINE_CONFIG config = { sizeof(config) };
169 
170     if(handle == HCCE_CURRENT_USER) {
171         if(!allow_default)
172             return NULL;
173 
174         if(!default_cu_engine) {
175             handle = CRYPT_CreateChainEngine(NULL, CERT_SYSTEM_STORE_CURRENT_USER, &config);
176             InterlockedCompareExchangePointer((void**)&default_cu_engine, handle, NULL);
177             if(default_cu_engine != handle)
178                 CertFreeCertificateChainEngine(handle);
179         }
180 
181         return default_cu_engine;
182     }
183 
184     if(handle == HCCE_LOCAL_MACHINE) {
185         if(!allow_default)
186             return NULL;
187 
188         if(!default_lm_engine) {
189             handle = CRYPT_CreateChainEngine(NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, &config);
190             InterlockedCompareExchangePointer((void**)&default_lm_engine, handle, NULL);
191             if(default_lm_engine != handle)
192                 CertFreeCertificateChainEngine(handle);
193         }
194 
195         return default_lm_engine;
196     }
197 
198     return (CertificateChainEngine*)handle;
199 }
200 
201 static void free_chain_engine(CertificateChainEngine *engine)
202 {
203     if(!engine || InterlockedDecrement(&engine->ref))
204         return;
205 
206     CertCloseStore(engine->hWorld, 0);
207     CertCloseStore(engine->hRoot, 0);
208     CryptMemFree(engine);
209 }
210 
211 typedef struct _CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT
212 {
213     DWORD       cbSize;
214     HCERTSTORE  hRestrictedRoot;
215     HCERTSTORE  hRestrictedTrust;
216     HCERTSTORE  hRestrictedOther;
217     DWORD       cAdditionalStore;
218     HCERTSTORE *rghAdditionalStore;
219     DWORD       dwFlags;
220     DWORD       dwUrlRetrievalTimeout;
221     DWORD       MaximumCachedCertificates;
222     DWORD       CycleDetectionModulus;
223 } CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT;
224 
225 BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
226  HCERTCHAINENGINE *phChainEngine)
227 {
228     BOOL ret;
229 
230     TRACE("(%p, %p)\n", pConfig, phChainEngine);
231 
232     if (pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT)
233      && pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG))
234     {
235         SetLastError(E_INVALIDARG);
236         return FALSE;
237     }
238     ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot);
239     if (!ret)
240     {
241         *phChainEngine = NULL;
242         return FALSE;
243     }
244 
245     *phChainEngine = CRYPT_CreateChainEngine(NULL, CERT_SYSTEM_STORE_CURRENT_USER, pConfig);
246     return *phChainEngine != NULL;
247 }
248 
249 void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
250 {
251     TRACE("(%p)\n", hChainEngine);
252     free_chain_engine(get_chain_engine(hChainEngine, FALSE));
253 }
254 
255 void default_chain_engine_free(void)
256 {
257     free_chain_engine(default_cu_engine);
258     free_chain_engine(default_lm_engine);
259 }
260 
261 typedef struct _CertificateChain
262 {
263     CERT_CHAIN_CONTEXT context;
264     HCERTSTORE world;
265     LONG ref;
266 } CertificateChain;
267 
268 BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert, DWORD *type)
269 {
270     PCERT_EXTENSION ext;
271     DWORD size;
272     BOOL ret;
273 
274     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
275      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
276     {
277         CERT_AUTHORITY_KEY_ID2_INFO *info;
278 
279         ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
280          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
281          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
282          &info, &size);
283         if (ret)
284         {
285             if (info->AuthorityCertIssuer.cAltEntry &&
286              info->AuthorityCertSerialNumber.cbData)
287             {
288                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
289                 DWORD i;
290 
291                 for (i = 0; !directoryName &&
292                  i < info->AuthorityCertIssuer.cAltEntry; i++)
293                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
294                      == CERT_ALT_NAME_DIRECTORY_NAME)
295                         directoryName =
296                          &info->AuthorityCertIssuer.rgAltEntry[i];
297                 if (directoryName)
298                 {
299                     ret = CertCompareCertificateName(cert->dwCertEncodingType,
300                      &directoryName->u.DirectoryName, &cert->pCertInfo->Issuer)
301                      && CertCompareIntegerBlob(&info->AuthorityCertSerialNumber,
302                      &cert->pCertInfo->SerialNumber);
303                      if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
304                 }
305                 else
306                 {
307                     FIXME("no supported name type in authority key id2\n");
308                     ret = FALSE;
309                 }
310             }
311             else if (info->KeyId.cbData)
312             {
313                 ret = CertGetCertificateContextProperty(cert,
314                  CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
315                 if (ret && size == info->KeyId.cbData)
316                 {
317                     LPBYTE buf = CryptMemAlloc(size);
318 
319                     if (buf)
320                     {
321                         CertGetCertificateContextProperty(cert,
322                          CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
323                         ret = !memcmp(buf, info->KeyId.pbData, size);
324                         CryptMemFree(buf);
325                         if (type) *type = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
326                     }
327                     else
328                         ret = FALSE;
329                 }
330                 else
331                     ret = FALSE;
332             }
333             LocalFree(info);
334         }
335     }
336     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
337      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension)))
338     {
339         CERT_AUTHORITY_KEY_ID_INFO *info;
340 
341         ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
342          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
343          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
344          &info, &size);
345         if (ret)
346         {
347             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
348             {
349                 ret = CertCompareCertificateName(cert->dwCertEncodingType,
350                  &info->CertIssuer, &cert->pCertInfo->Issuer) &&
351                  CertCompareIntegerBlob(&info->CertSerialNumber,
352                  &cert->pCertInfo->SerialNumber);
353                 if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
354             }
355             else if (info->KeyId.cbData)
356             {
357                 ret = CertGetCertificateContextProperty(cert,
358                  CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
359                 if (ret && size == info->KeyId.cbData)
360                 {
361                     LPBYTE buf = CryptMemAlloc(size);
362 
363                     if (buf)
364                     {
365                         CertGetCertificateContextProperty(cert,
366                          CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
367                         ret = !memcmp(buf, info->KeyId.pbData, size);
368                         CryptMemFree(buf);
369                         if (type) *type = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
370                     }
371                     else
372                         ret = FALSE;
373                 }
374                 else
375                     ret = FALSE;
376             }
377             else
378                 ret = FALSE;
379             LocalFree(info);
380         }
381     }
382     else
383     {
384         ret = CertCompareCertificateName(cert->dwCertEncodingType,
385          &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
386         if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
387     }
388     return ret;
389 }
390 
391 static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
392 {
393     CertFreeCertificateContext(element->pCertContext);
394     CryptMemFree(element);
395 }
396 
397 static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain)
398 {
399     DWORD i, j, cyclicCertIndex = 0;
400 
401     /* O(n^2) - I don't think there's a faster way */
402     for (i = 0; !cyclicCertIndex && i < chain->cElement; i++)
403         for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++)
404             if (CertCompareCertificate(X509_ASN_ENCODING,
405              chain->rgpElement[i]->pCertContext->pCertInfo,
406              chain->rgpElement[j]->pCertContext->pCertInfo))
407                 cyclicCertIndex = j;
408     if (cyclicCertIndex)
409     {
410         chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus
411          |= CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
412         /* Release remaining certs */
413         for (i = cyclicCertIndex + 1; i < chain->cElement; i++)
414             CRYPT_FreeChainElement(chain->rgpElement[i]);
415         /* Truncate chain */
416         chain->cElement = cyclicCertIndex + 1;
417     }
418 }
419 
420 /* Checks whether the chain is cyclic by examining the last element's status */
421 static inline BOOL CRYPT_IsSimpleChainCyclic(const CERT_SIMPLE_CHAIN *chain)
422 {
423     if (chain->cElement)
424         return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus
425          & CERT_TRUST_IS_CYCLIC;
426     else
427         return FALSE;
428 }
429 
430 static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus,
431  const CERT_TRUST_STATUS *elementStatus)
432 {
433     /* Any error that applies to an element also applies to a chain.. */
434     chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus;
435     /* but the bottom nibble of an element's info status doesn't apply to the
436      * chain.
437      */
438     chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0);
439 }
440 
441 static BOOL CRYPT_AddCertToSimpleChain(const CertificateChainEngine *engine,
442  PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus)
443 {
444     BOOL ret = FALSE;
445     PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
446 
447     if (element)
448     {
449         if (!chain->cElement)
450             chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT));
451         else
452             chain->rgpElement = CryptMemRealloc(chain->rgpElement,
453              (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
454         if (chain->rgpElement)
455         {
456             chain->rgpElement[chain->cElement++] = element;
457             memset(element, 0, sizeof(CERT_CHAIN_ELEMENT));
458             element->cbSize = sizeof(CERT_CHAIN_ELEMENT);
459             element->pCertContext = CertDuplicateCertificateContext(cert);
460             if (chain->cElement > 1)
461                 chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus
462                  = subjectInfoStatus;
463             /* FIXME: initialize the rest of element */
464             if (!(chain->cElement % engine->CycleDetectionModulus))
465             {
466                 CRYPT_CheckSimpleChainForCycles(chain);
467                 /* Reinitialize the element pointer in case the chain is
468                  * cyclic, in which case the chain is truncated.
469                  */
470                 element = chain->rgpElement[chain->cElement - 1];
471             }
472             CRYPT_CombineTrustStatus(&chain->TrustStatus,
473              &element->TrustStatus);
474             ret = TRUE;
475         }
476         else
477             CryptMemFree(element);
478     }
479     return ret;
480 }
481 
482 static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
483 {
484     DWORD i;
485 
486     for (i = 0; i < chain->cElement; i++)
487         CRYPT_FreeChainElement(chain->rgpElement[i]);
488     CryptMemFree(chain->rgpElement);
489     CryptMemFree(chain);
490 }
491 
492 static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot,
493  PCERT_CHAIN_ELEMENT rootElement)
494 {
495     PCCERT_CONTEXT trustedRoot = CRYPT_FindCertInStore(hRoot,
496      rootElement->pCertContext);
497 
498     if (!trustedRoot)
499         rootElement->TrustStatus.dwErrorStatus |=
500          CERT_TRUST_IS_UNTRUSTED_ROOT;
501     else
502         CertFreeCertificateContext(trustedRoot);
503 }
504 
505 static void CRYPT_CheckRootCert(HCERTSTORE hRoot,
506  PCERT_CHAIN_ELEMENT rootElement)
507 {
508     PCCERT_CONTEXT root = rootElement->pCertContext;
509 
510     if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType,
511      CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
512      CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
513     {
514         TRACE_(chain)("Last certificate's signature is invalid\n");
515         rootElement->TrustStatus.dwErrorStatus |=
516          CERT_TRUST_IS_NOT_SIGNATURE_VALID;
517     }
518     CRYPT_CheckTrustedStatus(hRoot, rootElement);
519 }
520 
521 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
522  * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a
523  * CERT_BASIC_CONSTRAINTS2_INFO.  If it neither extension is present, sets
524  * constraints->fCA to defaultIfNotSpecified.
525  * Returns FALSE if the extension is present but couldn't be decoded.
526  */
527 static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
528  CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified)
529 {
530     BOOL ret = TRUE;
531     PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
532      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
533 
534     constraints->fPathLenConstraint = FALSE;
535     if (ext)
536     {
537         CERT_BASIC_CONSTRAINTS_INFO *info;
538         DWORD size = 0;
539 
540         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
541          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
542          NULL, &info, &size);
543         if (ret)
544         {
545             if (info->SubjectType.cbData == 1)
546                 constraints->fCA =
547                  info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
548             LocalFree(info);
549         }
550     }
551     else
552     {
553         ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
554          cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
555         if (ext)
556         {
557             DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
558 
559             ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
560              szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
561              0, NULL, constraints, &size);
562         }
563         else
564             constraints->fCA = defaultIfNotSpecified;
565     }
566     return ret;
567 }
568 
569 /* Checks element's basic constraints to see if it can act as a CA, with
570  * remainingCAs CAs left in this chain.  In general, a cert must include the
571  * basic constraints extension, with the CA flag asserted, in order to be
572  * allowed to be a CA.  A V1 or V2 cert, which has no extensions, is also
573  * allowed to be a CA if it's installed locally (in the engine's world store.)
574  * This matches the expected usage in RFC 5280, section 4.2.1.9:  a conforming
575  * CA MUST include the basic constraints extension in all certificates that are
576  * used to validate digital signatures on certificates.  It also matches
577  * section 6.1.4(k): "If a certificate is a v1 or v2 certificate, then the
578  * application MUST either verify that the certificate is a CA certificate
579  * through out-of-band means or reject the certificate." Rejecting the
580  * certificate prohibits a large number of commonly used certificates, so
581  * accepting locally installed ones is a compromise.
582  * Root certificates are also allowed to be CAs even without a basic
583  * constraints extension.  This is implied by RFC 5280, section 6.1:  the
584  * root of a certificate chain's only requirement is that it was used to issue
585  * the next certificate in the chain.
586  * Updates chainConstraints with the element's constraints, if:
587  * 1. chainConstraints doesn't have a path length constraint, or
588  * 2. element's path length constraint is smaller than chainConstraints's
589  * Sets *pathLengthConstraintViolated to TRUE if a path length violation
590  * occurs.
591  * Returns TRUE if the element can be a CA, and the length of the remaining
592  * chain is valid.
593  */
594 static BOOL CRYPT_CheckBasicConstraintsForCA(CertificateChainEngine *engine,
595  PCCERT_CONTEXT cert, CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints,
596  DWORD remainingCAs, BOOL isRoot, BOOL *pathLengthConstraintViolated)
597 {
598     BOOL validBasicConstraints, implicitCA = FALSE;
599     CERT_BASIC_CONSTRAINTS2_INFO constraints;
600 
601     if (isRoot)
602         implicitCA = TRUE;
603     else if (cert->pCertInfo->dwVersion == CERT_V1 ||
604      cert->pCertInfo->dwVersion == CERT_V2)
605     {
606         BYTE hash[20];
607         DWORD size = sizeof(hash);
608 
609         if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
610          hash, &size))
611         {
612             CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
613             PCCERT_CONTEXT localCert = CertFindCertificateInStore(
614              engine->hWorld, cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
615              &blob, NULL);
616 
617             if (localCert)
618             {
619                 CertFreeCertificateContext(localCert);
620                 implicitCA = TRUE;
621             }
622         }
623     }
624     if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
625      &constraints, implicitCA)))
626     {
627         chainConstraints->fCA = constraints.fCA;
628         if (!constraints.fCA)
629         {
630             TRACE_(chain)("chain element %d can't be a CA\n", remainingCAs + 1);
631             validBasicConstraints = FALSE;
632         }
633         else if (constraints.fPathLenConstraint)
634         {
635             /* If the element has path length constraints, they apply to the
636              * entire remaining chain.
637              */
638             if (!chainConstraints->fPathLenConstraint ||
639              constraints.dwPathLenConstraint <
640              chainConstraints->dwPathLenConstraint)
641             {
642                 TRACE_(chain)("setting path length constraint to %d\n",
643                  chainConstraints->dwPathLenConstraint);
644                 chainConstraints->fPathLenConstraint = TRUE;
645                 chainConstraints->dwPathLenConstraint =
646                  constraints.dwPathLenConstraint;
647             }
648         }
649     }
650     if (chainConstraints->fPathLenConstraint &&
651      remainingCAs > chainConstraints->dwPathLenConstraint)
652     {
653         TRACE_(chain)("remaining CAs %d exceed max path length %d\n",
654          remainingCAs, chainConstraints->dwPathLenConstraint);
655         validBasicConstraints = FALSE;
656         *pathLengthConstraintViolated = TRUE;
657     }
658     return validBasicConstraints;
659 }
660 
661 static BOOL domain_name_matches(LPCWSTR constraint, LPCWSTR name)
662 {
663     BOOL match;
664 
665     /* RFC 5280, section 4.2.1.10:
666      * "For URIs, the constraint applies to the host part of the name...
667      *  When the constraint begins with a period, it MAY be expanded with one
668      *  or more labels.  That is, the constraint ".example.com" is satisfied by
669      *  both host.example.com and my.host.example.com.  However, the constraint
670      *  ".example.com" is not satisfied by "example.com".  When the constraint
671      *  does not begin with a period, it specifies a host."
672      * and for email addresses,
673      * "To indicate all Internet mail addresses on a particular host, the
674      *  constraint is specified as the host name.  For example, the constraint
675      *  "example.com" is satisfied by any mail address at the host
676      *  "example.com".  To specify any address within a domain, the constraint
677      *  is specified with a leading period (as with URIs)."
678      */
679     if (constraint[0] == '.')
680     {
681         /* Must be strictly greater than, a name can't begin with '.' */
682         if (lstrlenW(name) > lstrlenW(constraint))
683             match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
684              constraint);
685         else
686         {
687             /* name is too short, no match */
688             match = FALSE;
689         }
690     }
691     else
692         match = !lstrcmpiW(name, constraint);
693      return match;
694 }
695 
696 static BOOL url_matches(LPCWSTR constraint, LPCWSTR name,
697  DWORD *trustErrorStatus)
698 {
699     BOOL match = FALSE;
700 
701     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
702 
703     if (!constraint)
704         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
705     else if (!name)
706         ; /* no match */
707     else
708     {
709         LPCWSTR colon, authority_end, at, hostname = NULL;
710         /* The maximum length for a hostname is 254 in the DNS, see RFC 1034 */
711         WCHAR hostname_buf[255];
712 
713         /* RFC 5280: only the hostname portion of the URL is compared.  From
714          * section 4.2.1.10:
715          * "For URIs, the constraint applies to the host part of the name.
716          *  The constraint MUST be specified as a fully qualified domain name
717          *  and MAY specify a host or a domain."
718          * The format for URIs is in RFC 2396.
719          *
720          * First, remove any scheme that's present. */
721         colon = strchrW(name, ':');
722         if (colon && *(colon + 1) == '/' && *(colon + 2) == '/')
723             name = colon + 3;
724         /* Next, find the end of the authority component.  (The authority is
725          * generally just the hostname, but it may contain a username or a port.
726          * Those are removed next.)
727          */
728         authority_end = strchrW(name, '/');
729         if (!authority_end)
730             authority_end = strchrW(name, '?');
731         if (!authority_end)
732             authority_end = name + strlenW(name);
733         /* Remove any port number from the authority.  The userinfo portion
734          * of an authority may contain a colon, so stop if a userinfo portion
735          * is found (indicated by '@').
736          */
737         for (colon = authority_end; colon >= name && *colon != ':' &&
738          *colon != '@'; colon--)
739             ;
740         if (*colon == ':')
741             authority_end = colon;
742         /* Remove any username from the authority */
743         if ((at = strchrW(name, '@')))
744             name = at;
745         /* Ignore any path or query portion of the URL. */
746         if (*authority_end)
747         {
748             if (authority_end - name < sizeof(hostname_buf) /
749              sizeof(hostname_buf[0]))
750             {
751                 memcpy(hostname_buf, name,
752                  (authority_end - name) * sizeof(WCHAR));
753                 hostname_buf[authority_end - name] = 0;
754                 hostname = hostname_buf;
755             }
756             /* else: Hostname is too long, not a match */
757         }
758         else
759             hostname = name;
760         if (hostname)
761             match = domain_name_matches(constraint, hostname);
762     }
763     return match;
764 }
765 
766 static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name,
767  DWORD *trustErrorStatus)
768 {
769     BOOL match = FALSE;
770     LPCWSTR at;
771 
772     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
773 
774     if (!constraint)
775         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
776     else if (!name)
777         ; /* no match */
778     else if (strchrW(constraint, '@'))
779         match = !lstrcmpiW(constraint, name);
780     else
781     {
782         if ((at = strchrW(name, '@')))
783             match = domain_name_matches(constraint, at + 1);
784         else
785             match = !lstrcmpiW(constraint, name);
786     }
787     return match;
788 }
789 
790 static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name,
791  DWORD *trustErrorStatus)
792 {
793     BOOL match = FALSE;
794 
795     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
796 
797     if (!constraint)
798         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
799     else if (!name)
800         ; /* no match */
801     /* RFC 5280, section 4.2.1.10:
802      * "DNS name restrictions are expressed as host.example.com.  Any DNS name
803      *  that can be constructed by simply adding zero or more labels to the
804      *  left-hand side of the name satisfies the name constraint.  For example,
805      *  www.host.example.com would satisfy the constraint but host1.example.com
806      *  would not."
807      */
808     else if (lstrlenW(name) == lstrlenW(constraint))
809         match = !lstrcmpiW(name, constraint);
810     else if (lstrlenW(name) > lstrlenW(constraint))
811     {
812         match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
813          constraint);
814         if (match)
815         {
816             BOOL dot = FALSE;
817             LPCWSTR ptr;
818 
819             /* This only matches if name is a subdomain of constraint, i.e.
820              * there's a '.' between the beginning of the name and the
821              * matching portion of the name.
822              */
823             for (ptr = name + lstrlenW(name) - lstrlenW(constraint);
824              !dot && ptr >= name; ptr--)
825                 if (*ptr == '.')
826                     dot = TRUE;
827             match = dot;
828         }
829     }
830     /* else:  name is too short, no match */
831 
832     return match;
833 }
834 
835 static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint,
836  const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus)
837 {
838     BOOL match = FALSE;
839 
840     TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData,
841      name->cbData, name->pbData);
842 
843     /* RFC5280, section 4.2.1.10, iPAddress syntax: either 8 or 32 bytes, for
844      * IPv4 or IPv6 addresses, respectively.
845      */
846     if (constraint->cbData != sizeof(DWORD) * 2 && constraint->cbData != 32)
847         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
848     else if (name->cbData == sizeof(DWORD) &&
849      constraint->cbData == sizeof(DWORD) * 2)
850     {
851         DWORD subnet, mask, addr;
852 
853         memcpy(&subnet, constraint->pbData, sizeof(subnet));
854         memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask));
855         memcpy(&addr, name->pbData, sizeof(addr));
856         /* These are really in big-endian order, but for equality matching we
857          * don't need to swap to host order
858          */
859         match = (subnet & mask) == (addr & mask);
860     }
861     else if (name->cbData == 16 && constraint->cbData == 32)
862     {
863         const BYTE *subnet, *mask, *addr;
864         DWORD i;
865 
866         subnet = constraint->pbData;
867         mask = constraint->pbData + 16;
868         addr = name->pbData;
869         match = TRUE;
870         for (i = 0; match && i < 16; i++)
871             if ((subnet[i] & mask[i]) != (addr[i] & mask[i]))
872                 match = FALSE;
873     }
874     /* else: name is wrong size, no match */
875 
876     return match;
877 }
878 
879 static BOOL directory_name_matches(const CERT_NAME_BLOB *constraint,
880  const CERT_NAME_BLOB *name)
881 {
882     CERT_NAME_INFO *constraintName;
883     DWORD size;
884     BOOL match = FALSE;
885 
886     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, constraint->pbData,
887      constraint->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &constraintName, &size))
888     {
889         DWORD i;
890 
891         match = TRUE;
892         for (i = 0; match && i < constraintName->cRDN; i++)
893             match = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING,
894              CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG,
895              (CERT_NAME_BLOB *)name, &constraintName->rgRDN[i]);
896         LocalFree(constraintName);
897     }
898     return match;
899 }
900 
901 static BOOL alt_name_matches(const CERT_ALT_NAME_ENTRY *name,
902  const CERT_ALT_NAME_ENTRY *constraint, DWORD *trustErrorStatus, BOOL *present)
903 {
904     BOOL match = FALSE;
905 
906     if (name->dwAltNameChoice == constraint->dwAltNameChoice)
907     {
908         if (present)
909             *present = TRUE;
910         switch (constraint->dwAltNameChoice)
911         {
912         case CERT_ALT_NAME_RFC822_NAME:
913             match = rfc822_name_matches(constraint->u.pwszURL,
914              name->u.pwszURL, trustErrorStatus);
915             break;
916         case CERT_ALT_NAME_DNS_NAME:
917             match = dns_name_matches(constraint->u.pwszURL,
918              name->u.pwszURL, trustErrorStatus);
919             break;
920         case CERT_ALT_NAME_URL:
921             match = url_matches(constraint->u.pwszURL,
922              name->u.pwszURL, trustErrorStatus);
923             break;
924         case CERT_ALT_NAME_IP_ADDRESS:
925             match = ip_address_matches(&constraint->u.IPAddress,
926              &name->u.IPAddress, trustErrorStatus);
927             break;
928         case CERT_ALT_NAME_DIRECTORY_NAME:
929             match = directory_name_matches(&constraint->u.DirectoryName,
930              &name->u.DirectoryName);
931             break;
932         default:
933             ERR("name choice %d unsupported in this context\n",
934              constraint->dwAltNameChoice);
935             *trustErrorStatus |=
936              CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
937         }
938     }
939     else if (present)
940         *present = FALSE;
941     return match;
942 }
943 
944 static BOOL alt_name_matches_excluded_name(const CERT_ALT_NAME_ENTRY *name,
945  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
946 {
947     DWORD i;
948     BOOL match = FALSE;
949 
950     for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++)
951         match = alt_name_matches(name,
952          &nameConstraints->rgExcludedSubtree[i].Base, trustErrorStatus, NULL);
953     return match;
954 }
955 
956 static BOOL alt_name_matches_permitted_name(const CERT_ALT_NAME_ENTRY *name,
957  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus,
958  BOOL *present)
959 {
960     DWORD i;
961     BOOL match = FALSE;
962 
963     for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
964         match = alt_name_matches(name,
965          &nameConstraints->rgPermittedSubtree[i].Base, trustErrorStatus,
966          present);
967     return match;
968 }
969 
970 static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert)
971 {
972     PCERT_EXTENSION ext;
973 
974     ext = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
975      cert->cExtension, cert->rgExtension);
976     if (!ext)
977         ext = CertFindExtension(szOID_SUBJECT_ALT_NAME,
978          cert->cExtension, cert->rgExtension);
979     return ext;
980 }
981 
982 static void compare_alt_name_with_constraints(const CERT_EXTENSION *altNameExt,
983  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
984 {
985     CERT_ALT_NAME_INFO *subjectAltName;
986     DWORD size;
987 
988     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
989      altNameExt->Value.pbData, altNameExt->Value.cbData,
990      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
991      &subjectAltName, &size))
992     {
993         DWORD i;
994 
995         for (i = 0; i < subjectAltName->cAltEntry; i++)
996         {
997              BOOL nameFormPresent;
998 
999              /* A name constraint only applies if the name form is present.
1000               * From RFC 5280, section 4.2.1.10:
1001               * "Restrictions apply only when the specified name form is
1002               *  present.  If no name of the type is in the certificate,
1003               *  the certificate is acceptable."
1004               */
1005             if (alt_name_matches_excluded_name(
1006              &subjectAltName->rgAltEntry[i], nameConstraints,
1007              trustErrorStatus))
1008             {
1009                 TRACE_(chain)("subject alternate name form %d excluded\n",
1010                  subjectAltName->rgAltEntry[i].dwAltNameChoice);
1011                 *trustErrorStatus |=
1012                  CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
1013             }
1014             nameFormPresent = FALSE;
1015             if (!alt_name_matches_permitted_name(
1016              &subjectAltName->rgAltEntry[i], nameConstraints,
1017              trustErrorStatus, &nameFormPresent) && nameFormPresent)
1018             {
1019                 TRACE_(chain)("subject alternate name form %d not permitted\n",
1020                  subjectAltName->rgAltEntry[i].dwAltNameChoice);
1021                 *trustErrorStatus |=
1022                  CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
1023             }
1024         }
1025         LocalFree(subjectAltName);
1026     }
1027     else
1028         *trustErrorStatus |=
1029          CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS;
1030 }
1031 
1032 static BOOL rfc822_attr_matches_excluded_name(const CERT_RDN_ATTR *attr,
1033  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
1034 {
1035     DWORD i;
1036     BOOL match = FALSE;
1037 
1038     for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++)
1039     {
1040         const CERT_ALT_NAME_ENTRY *constraint =
1041          &nameConstraints->rgExcludedSubtree[i].Base;
1042 
1043         if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
1044             match = rfc822_name_matches(constraint->u.pwszRfc822Name,
1045              (LPCWSTR)attr->Value.pbData, trustErrorStatus);
1046     }
1047     return match;
1048 }
1049 
1050 static BOOL rfc822_attr_matches_permitted_name(const CERT_RDN_ATTR *attr,
1051  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus,
1052  BOOL *present)
1053 {
1054     DWORD i;
1055     BOOL match = FALSE;
1056 
1057     for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
1058     {
1059         const CERT_ALT_NAME_ENTRY *constraint =
1060          &nameConstraints->rgPermittedSubtree[i].Base;
1061 
1062         if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
1063         {
1064             *present = TRUE;
1065             match = rfc822_name_matches(constraint->u.pwszRfc822Name,
1066              (LPCWSTR)attr->Value.pbData, trustErrorStatus);
1067         }
1068     }
1069     return match;
1070 }
1071 
1072 static void compare_subject_with_email_constraints(
1073  const CERT_NAME_BLOB *subjectName,
1074  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
1075 {
1076     CERT_NAME_INFO *name;
1077     DWORD size;
1078 
1079     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME,
1080      subjectName->pbData, subjectName->cbData,
1081      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size))
1082     {
1083         DWORD i, j;
1084 
1085         for (i = 0; i < name->cRDN; i++)
1086             for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
1087                 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
1088                  szOID_RSA_emailAddr))
1089                 {
1090                     BOOL nameFormPresent;
1091 
1092                     /* A name constraint only applies if the name form is
1093                      * present.  From RFC 5280, section 4.2.1.10:
1094                      * "Restrictions apply only when the specified name form is
1095                      *  present.  If no name of the type is in the certificate,
1096                      *  the certificate is acceptable."
1097                      */
1098                     if (rfc822_attr_matches_excluded_name(
1099                      &name->rgRDN[i].rgRDNAttr[j], nameConstraints,
1100                      trustErrorStatus))
1101                     {
1102                         TRACE_(chain)(
1103                          "email address in subject name is excluded\n");
1104                         *trustErrorStatus |=
1105                          CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
1106                     }
1107                     nameFormPresent = FALSE;
1108                     if (!rfc822_attr_matches_permitted_name(
1109                      &name->rgRDN[i].rgRDNAttr[j], nameConstraints,
1110                      trustErrorStatus, &nameFormPresent) && nameFormPresent)
1111                     {
1112                         TRACE_(chain)(
1113                          "email address in subject name is not permitted\n");
1114                         *trustErrorStatus |=
1115                          CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
1116                     }
1117                 }
1118         LocalFree(name);
1119     }
1120     else
1121         *trustErrorStatus |=
1122          CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS;
1123 }
1124 
1125 static BOOL CRYPT_IsEmptyName(const CERT_NAME_BLOB *name)
1126 {
1127     BOOL empty;
1128 
1129     if (!name->cbData)
1130         empty = TRUE;
1131     else if (name->cbData == 2 && name->pbData[1] == 0)
1132     {
1133         /* An empty sequence is also empty */
1134         empty = TRUE;
1135     }
1136     else
1137         empty = FALSE;
1138     return empty;
1139 }
1140 
1141 static void compare_subject_with_constraints(const CERT_NAME_BLOB *subjectName,
1142  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
1143 {
1144     BOOL hasEmailConstraint = FALSE;
1145     DWORD i;
1146 
1147     /* In general, a subject distinguished name only matches a directory name
1148      * constraint.  However, an exception exists for email addresses.
1149      * From RFC 5280, section 4.2.1.6:
1150      * "Legacy implementations exist where an electronic mail address is
1151      *  embedded in the subject distinguished name as an emailAddress
1152      *  attribute [RFC2985]."
1153      * If an email address constraint exists, check that constraint separately.
1154      */
1155     for (i = 0; !hasEmailConstraint && i < nameConstraints->cExcludedSubtree;
1156      i++)
1157         if (nameConstraints->rgExcludedSubtree[i].Base.dwAltNameChoice ==
1158          CERT_ALT_NAME_RFC822_NAME)
1159             hasEmailConstraint = TRUE;
1160     for (i = 0; !hasEmailConstraint && i < nameConstraints->cPermittedSubtree;
1161      i++)
1162         if (nameConstraints->rgPermittedSubtree[i].Base.dwAltNameChoice ==
1163          CERT_ALT_NAME_RFC822_NAME)
1164             hasEmailConstraint = TRUE;
1165     if (hasEmailConstraint)
1166         compare_subject_with_email_constraints(subjectName, nameConstraints,
1167          trustErrorStatus);
1168     for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
1169     {
1170         CERT_ALT_NAME_ENTRY *constraint =
1171          &nameConstraints->rgExcludedSubtree[i].Base;
1172 
1173         if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME &&
1174          directory_name_matches(&constraint->u.DirectoryName, subjectName))
1175         {
1176             TRACE_(chain)("subject name is excluded\n");
1177             *trustErrorStatus |=
1178              CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
1179         }
1180     }
1181     /* RFC 5280, section 4.2.1.10:
1182      * "Restrictions apply only when the specified name form is present.
1183      *  If no name of the type is in the certificate, the certificate is
1184      *  acceptable."
1185      * An empty name can't have the name form present, so don't check it.
1186      */
1187     if (nameConstraints->cPermittedSubtree && !CRYPT_IsEmptyName(subjectName))
1188     {
1189         BOOL match = FALSE, hasDirectoryConstraint = FALSE;
1190 
1191         for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
1192         {
1193             CERT_ALT_NAME_ENTRY *constraint =
1194              &nameConstraints->rgPermittedSubtree[i].Base;
1195 
1196             if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME)
1197             {
1198                 hasDirectoryConstraint = TRUE;
1199                 match = directory_name_matches(&constraint->u.DirectoryName,
1200                  subjectName);
1201             }
1202         }
1203         if (hasDirectoryConstraint && !match)
1204         {
1205             TRACE_(chain)("subject name is not permitted\n");
1206             *trustErrorStatus |= CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
1207         }
1208     }
1209 }
1210 
1211 static void CRYPT_CheckNameConstraints(
1212  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
1213  DWORD *trustErrorStatus)
1214 {
1215     CERT_EXTENSION *ext = get_subject_alt_name_ext(cert);
1216 
1217     if (ext)
1218         compare_alt_name_with_constraints(ext, nameConstraints,
1219          trustErrorStatus);
1220     /* Name constraints apply to the subject alternative name as well as the
1221      * subject name.  From RFC 5280, section 4.2.1.10:
1222      * "Restrictions apply to the subject distinguished name and apply to
1223      *  subject alternative names."
1224      */
1225     compare_subject_with_constraints(&cert->Subject, nameConstraints,
1226      trustErrorStatus);
1227 }
1228 
1229 /* Gets cert's name constraints, if any.  Free with LocalFree. */
1230 static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert)
1231 {
1232     CERT_NAME_CONSTRAINTS_INFO *info = NULL;
1233 
1234     CERT_EXTENSION *ext;
1235 
1236     if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension,
1237      cert->rgExtension)))
1238     {
1239         DWORD size;
1240 
1241         CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
1242          ext->Value.pbData, ext->Value.cbData,
1243          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info,
1244          &size);
1245     }
1246     return info;
1247 }
1248 
1249 static BOOL CRYPT_IsValidNameConstraint(const CERT_NAME_CONSTRAINTS_INFO *info)
1250 {
1251     DWORD i;
1252     BOOL ret = TRUE;
1253 
1254     /* Make sure at least one permitted or excluded subtree is present.  From
1255      * RFC 5280, section 4.2.1.10:
1256      * "Conforming CAs MUST NOT issue certificates where name constraints is an
1257      *  empty sequence.  That is, either the permittedSubtrees field or the
1258      *  excludedSubtrees MUST be present."
1259      */
1260     if (!info->cPermittedSubtree && !info->cExcludedSubtree)
1261     {
1262         WARN_(chain)("constraints contain no permitted nor excluded subtree\n");
1263         ret = FALSE;
1264     }
1265     /* Check that none of the constraints specifies a minimum or a maximum.
1266      * See RFC 5280, section 4.2.1.10:
1267      * "Within this profile, the minimum and maximum fields are not used with
1268      *  any name forms, thus, the minimum MUST be zero, and maximum MUST be
1269      *  absent.  However, if an application encounters a critical name
1270      *  constraints extension that specifies other values for minimum or
1271      *  maximum for a name form that appears in a subsequent certificate, the
1272      *  application MUST either process these fields or reject the
1273      *  certificate."
1274      * Since it gives no guidance as to how to process these fields, we
1275      * reject any name constraint that contains them.
1276      */
1277     for (i = 0; ret && i < info->cPermittedSubtree; i++)
1278         if (info->rgPermittedSubtree[i].dwMinimum ||
1279          info->rgPermittedSubtree[i].fMaximum)
1280         {
1281             TRACE_(chain)("found a minimum or maximum in permitted subtrees\n");
1282             ret = FALSE;
1283         }
1284     for (i = 0; ret && i < info->cExcludedSubtree; i++)
1285         if (info->rgExcludedSubtree[i].dwMinimum ||
1286          info->rgExcludedSubtree[i].fMaximum)
1287         {
1288             TRACE_(chain)("found a minimum or maximum in excluded subtrees\n");
1289             ret = FALSE;
1290         }
1291     return ret;
1292 }
1293 
1294 static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
1295 {
1296     int i, j;
1297 
1298     /* Microsoft's implementation appears to violate RFC 3280:  according to
1299      * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's
1300      * name constraint is violated in the end cert.  According to RFC 3280,
1301      * the constraints should be checked against every subsequent certificate
1302      * in the chain, not just the end cert.
1303      * Microsoft's implementation also sets the name constraint errors on the
1304      * certs whose constraints were violated, not on the certs that violated
1305      * them.
1306      * In order to be error-compatible with Microsoft's implementation, while
1307      * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name
1308      * constraints.
1309      */
1310     for (i = chain->cElement - 1; i > 0; i--)
1311     {
1312         CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
1313 
1314         if ((nameConstraints = CRYPT_GetNameConstraints(
1315          chain->rgpElement[i]->pCertContext->pCertInfo)))
1316         {
1317             if (!CRYPT_IsValidNameConstraint(nameConstraints))
1318                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1319                  CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
1320             else
1321             {
1322                 for (j = i - 1; j >= 0; j--)
1323                 {
1324                     DWORD errorStatus = 0;
1325 
1326                     /* According to RFC 3280, self-signed certs don't have name
1327                      * constraints checked unless they're the end cert.
1328                      */
1329                     if (j == 0 || !CRYPT_IsCertificateSelfSigned(
1330                      chain->rgpElement[j]->pCertContext, NULL))
1331                     {
1332                         CRYPT_CheckNameConstraints(nameConstraints,
1333                          chain->rgpElement[j]->pCertContext->pCertInfo,
1334                          &errorStatus);
1335                         if (errorStatus)
1336                         {
1337                             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1338                              errorStatus;
1339                             CRYPT_CombineTrustStatus(&chain->TrustStatus,
1340                              &chain->rgpElement[i]->TrustStatus);
1341                         }
1342                         else
1343                             chain->rgpElement[i]->TrustStatus.dwInfoStatus |=
1344                              CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS;
1345                     }
1346                 }
1347             }
1348             LocalFree(nameConstraints);
1349         }
1350     }
1351 }
1352 
1353 /* Gets cert's policies info, if any.  Free with LocalFree. */
1354 static CERT_POLICIES_INFO *CRYPT_GetPolicies(PCCERT_CONTEXT cert)
1355 {
1356     PCERT_EXTENSION ext;
1357     CERT_POLICIES_INFO *policies = NULL;
1358 
1359     ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension,
1360      cert->pCertInfo->rgExtension);
1361     if (ext)
1362     {
1363         DWORD size;
1364 
1365         CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
1366          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1367          &policies, &size);
1368     }
1369     return policies;
1370 }
1371 
1372 static void CRYPT_CheckPolicies(const CERT_POLICIES_INFO *policies, CERT_INFO *cert,
1373  DWORD *errorStatus)
1374 {
1375     DWORD i;
1376 
1377     for (i = 0; i < policies->cPolicyInfo; i++)
1378     {
1379         /* For now, the only accepted policy identifier is the anyPolicy
1380          * identifier.
1381          * FIXME: the policy identifiers should be compared against the
1382          * cert's certificate policies extension, subject to the policy
1383          * mappings extension, and the policy constraints extension.
1384          * See RFC 5280, sections 4.2.1.4, 4.2.1.5, and 4.2.1.11.
1385          */
1386         if (strcmp(policies->rgPolicyInfo[i].pszPolicyIdentifier,
1387          szOID_ANY_CERT_POLICY))
1388         {
1389             FIXME("unsupported policy %s\n",
1390              policies->rgPolicyInfo[i].pszPolicyIdentifier);
1391             *errorStatus |= CERT_TRUST_INVALID_POLICY_CONSTRAINTS;
1392         }
1393     }
1394 }
1395 
1396 static void CRYPT_CheckChainPolicies(PCERT_SIMPLE_CHAIN chain)
1397 {
1398     int i, j;
1399 
1400     for (i = chain->cElement - 1; i > 0; i--)
1401     {
1402         CERT_POLICIES_INFO *policies;
1403 
1404         if ((policies = CRYPT_GetPolicies(chain->rgpElement[i]->pCertContext)))
1405         {
1406             for (j = i - 1; j >= 0; j--)
1407             {
1408                 DWORD errorStatus = 0;
1409 
1410                 CRYPT_CheckPolicies(policies,
1411                  chain->rgpElement[j]->pCertContext->pCertInfo, &errorStatus);
1412                 if (errorStatus)
1413                 {
1414                     chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1415                      errorStatus;
1416                     CRYPT_CombineTrustStatus(&chain->TrustStatus,
1417                      &chain->rgpElement[i]->TrustStatus);
1418                 }
1419             }
1420             LocalFree(policies);
1421         }
1422     }
1423 }
1424 
1425 static LPWSTR name_value_to_str(const CERT_NAME_BLOB *name)
1426 {
1427     DWORD len = cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name,
1428      CERT_SIMPLE_NAME_STR, NULL, 0);
1429     LPWSTR str = NULL;
1430 
1431     if (len)
1432     {
1433         str = CryptMemAlloc(len * sizeof(WCHAR));
1434         if (str)
1435             cert_name_to_str_with_indent(X509_ASN_ENCODING, 0, name,
1436              CERT_SIMPLE_NAME_STR, str, len);
1437     }
1438     return str;
1439 }
1440 
1441 static void dump_alt_name_entry(const CERT_ALT_NAME_ENTRY *entry)
1442 {
1443     LPWSTR str;
1444 
1445     switch (entry->dwAltNameChoice)
1446     {
1447     case CERT_ALT_NAME_OTHER_NAME:
1448         TRACE_(chain)("CERT_ALT_NAME_OTHER_NAME, oid = %s\n",
1449          debugstr_a(entry->u.pOtherName->pszObjId));
1450          break;
1451     case CERT_ALT_NAME_RFC822_NAME:
1452         TRACE_(chain)("CERT_ALT_NAME_RFC822_NAME: %s\n",
1453          debugstr_w(entry->u.pwszRfc822Name));
1454         break;
1455     case CERT_ALT_NAME_DNS_NAME:
1456         TRACE_(chain)("CERT_ALT_NAME_DNS_NAME: %s\n",
1457          debugstr_w(entry->u.pwszDNSName));
1458         break;
1459     case CERT_ALT_NAME_DIRECTORY_NAME:
1460         str = name_value_to_str(&entry->u.DirectoryName);
1461         TRACE_(chain)("CERT_ALT_NAME_DIRECTORY_NAME: %s\n", debugstr_w(str));
1462         CryptMemFree(str);
1463         break;
1464     case CERT_ALT_NAME_URL:
1465         TRACE_(chain)("CERT_ALT_NAME_URL: %s\n", debugstr_w(entry->u.pwszURL));
1466         break;
1467     case CERT_ALT_NAME_IP_ADDRESS:
1468         TRACE_(chain)("CERT_ALT_NAME_IP_ADDRESS: %d bytes\n",
1469          entry->u.IPAddress.cbData);
1470         break;
1471     case CERT_ALT_NAME_REGISTERED_ID:
1472         TRACE_(chain)("CERT_ALT_NAME_REGISTERED_ID: %s\n",
1473          debugstr_a(entry->u.pszRegisteredID));
1474         break;
1475     default:
1476         TRACE_(chain)("dwAltNameChoice = %d\n", entry->dwAltNameChoice);
1477     }
1478 }
1479 
1480 static void dump_alt_name(LPCSTR type, const CERT_EXTENSION *ext)
1481 {
1482     CERT_ALT_NAME_INFO *name;
1483     DWORD size;
1484 
1485     TRACE_(chain)("%s:\n", type);
1486     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
1487      ext->Value.pbData, ext->Value.cbData,
1488      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size))
1489     {
1490         DWORD i;
1491 
1492         TRACE_(chain)("%d alt name entries:\n", name->cAltEntry);
1493         for (i = 0; i < name->cAltEntry; i++)
1494             dump_alt_name_entry(&name->rgAltEntry[i]);
1495         LocalFree(name);
1496     }
1497 }
1498 
1499 static void dump_basic_constraints(const CERT_EXTENSION *ext)
1500 {
1501     CERT_BASIC_CONSTRAINTS_INFO *info;
1502     DWORD size = 0;
1503 
1504     if (CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
1505      ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
1506      NULL, &info, &size))
1507     {
1508         TRACE_(chain)("SubjectType: %02x\n", info->SubjectType.pbData[0]);
1509         TRACE_(chain)("%s path length constraint\n",
1510          info->fPathLenConstraint ? "has" : "doesn't have");
1511         TRACE_(chain)("path length=%d\n", info->dwPathLenConstraint);
1512         LocalFree(info);
1513     }
1514 }
1515 
1516 static void dump_basic_constraints2(const CERT_EXTENSION *ext)
1517 {
1518     CERT_BASIC_CONSTRAINTS2_INFO constraints;
1519     DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
1520 
1521     if (CryptDecodeObjectEx(X509_ASN_ENCODING,
1522      szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
1523      0, NULL, &constraints, &size))
1524     {
1525         TRACE_(chain)("basic constraints:\n");
1526         TRACE_(chain)("can%s be a CA\n", constraints.fCA ? "" : "not");
1527         TRACE_(chain)("%s path length constraint\n",
1528          constraints.fPathLenConstraint ? "has" : "doesn't have");
1529         TRACE_(chain)("path length=%d\n", constraints.dwPathLenConstraint);
1530     }
1531 }
1532 
1533 static void dump_key_usage(const CERT_EXTENSION *ext)
1534 {
1535     CRYPT_BIT_BLOB usage;
1536     DWORD size = sizeof(usage);
1537 
1538     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData,
1539      ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
1540     {
1541 #define trace_usage_bit(bits, bit) \
1542  if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
1543         if (usage.cbData)
1544         {
1545             trace_usage_bit(usage.pbData[0], CERT_DIGITAL_SIGNATURE_KEY_USAGE);
1546             trace_usage_bit(usage.pbData[0], CERT_NON_REPUDIATION_KEY_USAGE);
1547             trace_usage_bit(usage.pbData[0], CERT_KEY_ENCIPHERMENT_KEY_USAGE);
1548             trace_usage_bit(usage.pbData[0], CERT_DATA_ENCIPHERMENT_KEY_USAGE);
1549             trace_usage_bit(usage.pbData[0], CERT_KEY_AGREEMENT_KEY_USAGE);
1550             trace_usage_bit(usage.pbData[0], CERT_KEY_CERT_SIGN_KEY_USAGE);
1551             trace_usage_bit(usage.pbData[0], CERT_CRL_SIGN_KEY_USAGE);
1552             trace_usage_bit(usage.pbData[0], CERT_ENCIPHER_ONLY_KEY_USAGE);
1553         }
1554 #undef trace_usage_bit
1555         if (usage.cbData > 1 && usage.pbData[1] & CERT_DECIPHER_ONLY_KEY_USAGE)
1556             TRACE_(chain)("CERT_DECIPHER_ONLY_KEY_USAGE\n");
1557     }
1558 }
1559 
1560 static void dump_general_subtree(const CERT_GENERAL_SUBTREE *subtree)
1561 {
1562     dump_alt_name_entry(&subtree->Base);
1563     TRACE_(chain)("dwMinimum = %d, fMaximum = %d, dwMaximum = %d\n",
1564      subtree->dwMinimum, subtree->fMaximum, subtree->dwMaximum);
1565 }
1566 
1567 static void dump_name_constraints(const CERT_EXTENSION *ext)
1568 {
1569     CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
1570     DWORD size;
1571 
1572     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
1573      ext->Value.pbData, ext->Value.cbData,
1574      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &nameConstraints,
1575      &size))
1576     {
1577         DWORD i;
1578 
1579         TRACE_(chain)("%d permitted subtrees:\n",
1580          nameConstraints->cPermittedSubtree);
1581         for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
1582             dump_general_subtree(&nameConstraints->rgPermittedSubtree[i]);
1583         TRACE_(chain)("%d excluded subtrees:\n",
1584          nameConstraints->cExcludedSubtree);
1585         for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
1586             dump_general_subtree(&nameConstraints->rgExcludedSubtree[i]);
1587         LocalFree(nameConstraints);
1588     }
1589 }
1590 
1591 static void dump_cert_policies(const CERT_EXTENSION *ext)
1592 {
1593     CERT_POLICIES_INFO *policies;
1594     DWORD size;
1595 
1596     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT_POLICIES,
1597      ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1598      &policies, &size))
1599     {
1600         DWORD i, j;
1601 
1602         TRACE_(chain)("%d policies:\n", policies->cPolicyInfo);
1603         for (i = 0; i < policies->cPolicyInfo; i++)
1604         {
1605             TRACE_(chain)("policy identifier: %s\n",
1606              debugstr_a(policies->rgPolicyInfo[i].pszPolicyIdentifier));
1607             TRACE_(chain)("%d policy qualifiers:\n",
1608              policies->rgPolicyInfo[i].cPolicyQualifier);
1609             for (j = 0; j < policies->rgPolicyInfo[i].cPolicyQualifier; j++)
1610                 TRACE_(chain)("%s\n", debugstr_a(
1611                  policies->rgPolicyInfo[i].rgPolicyQualifier[j].
1612                  pszPolicyQualifierId));
1613         }
1614         LocalFree(policies);
1615     }
1616 }
1617 
1618 static void dump_enhanced_key_usage(const CERT_EXTENSION *ext)
1619 {
1620     CERT_ENHKEY_USAGE *usage;
1621     DWORD size;
1622 
1623     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
1624      ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL,
1625      &usage, &size))
1626     {
1627         DWORD i;
1628 
1629         TRACE_(chain)("%d usages:\n", usage->cUsageIdentifier);
1630         for (i = 0; i < usage->cUsageIdentifier; i++)
1631             TRACE_(chain)("%s\n", usage->rgpszUsageIdentifier[i]);
1632         LocalFree(usage);
1633     }
1634 }
1635 
1636 static void dump_netscape_cert_type(const CERT_EXTENSION *ext)
1637 {
1638     CRYPT_BIT_BLOB usage;
1639     DWORD size = sizeof(usage);
1640 
1641     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_BITS, ext->Value.pbData,
1642      ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &usage, &size))
1643     {
1644 #define trace_cert_type_bit(bits, bit) \
1645  if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
1646         if (usage.cbData)
1647         {
1648             trace_cert_type_bit(usage.pbData[0],
1649              NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE);
1650             trace_cert_type_bit(usage.pbData[0],
1651              NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE);
1652             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CERT_TYPE);
1653             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CERT_TYPE);
1654             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SSL_CA_CERT_TYPE);
1655             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SMIME_CA_CERT_TYPE);
1656             trace_cert_type_bit(usage.pbData[0], NETSCAPE_SIGN_CA_CERT_TYPE);
1657         }
1658 #undef trace_cert_type_bit
1659     }
1660 }
1661 
1662 static void dump_extension(const CERT_EXTENSION *ext)
1663 {
1664     TRACE_(chain)("%s (%scritical)\n", debugstr_a(ext->pszObjId),
1665      ext->fCritical ? "" : "not ");
1666     if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME))
1667         dump_alt_name("subject alt name", ext);
1668     else  if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME))
1669         dump_alt_name("issuer alt name", ext);
1670     else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS))
1671         dump_basic_constraints(ext);
1672     else if (!strcmp(ext->pszObjId, szOID_KEY_USAGE))
1673         dump_key_usage(ext);
1674     else if (!strcmp(ext->pszObjId, szOID_SUBJECT_ALT_NAME2))
1675         dump_alt_name("subject alt name 2", ext);
1676     else if (!strcmp(ext->pszObjId, szOID_ISSUER_ALT_NAME2))
1677         dump_alt_name("issuer alt name 2", ext);
1678     else if (!strcmp(ext->pszObjId, szOID_BASIC_CONSTRAINTS2))
1679         dump_basic_constraints2(ext);
1680     else if (!strcmp(ext->pszObjId, szOID_NAME_CONSTRAINTS))
1681         dump_name_constraints(ext);
1682     else if (!strcmp(ext->pszObjId, szOID_CERT_POLICIES))
1683         dump_cert_policies(ext);
1684     else if (!strcmp(ext->pszObjId, szOID_ENHANCED_KEY_USAGE))
1685         dump_enhanced_key_usage(ext);
1686     else if (!strcmp(ext->pszObjId, szOID_NETSCAPE_CERT_TYPE))
1687         dump_netscape_cert_type(ext);
1688 }
1689 
1690 static LPCSTR filetime_to_str(const FILETIME *time)
1691 {
1692     char date[80];
1693     char dateFmt[80]; /* sufficient for all versions of LOCALE_SSHORTDATE */
1694     SYSTEMTIME sysTime;
1695 
1696     if (!time) return "(null)";
1697 
1698     GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SSHORTDATE, dateFmt,
1699      sizeof(dateFmt) / sizeof(dateFmt[0]));
1700     FileTimeToSystemTime(time, &sysTime);
1701     GetDateFormatA(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, dateFmt, date,
1702      sizeof(date) / sizeof(date[0]));
1703     return wine_dbg_sprintf("%s", date);
1704 }
1705 
1706 static void dump_element(PCCERT_CONTEXT cert)
1707 {
1708     LPWSTR name = NULL;
1709     DWORD len, i;
1710 
1711     TRACE_(chain)("%p: version %d\n", cert, cert->pCertInfo->dwVersion);
1712     len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
1713      CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
1714     name = CryptMemAlloc(len * sizeof(WCHAR));
1715     if (name)
1716     {
1717         CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
1718          CERT_NAME_ISSUER_FLAG, NULL, name, len);
1719         TRACE_(chain)("issued by %s\n", debugstr_w(name));
1720         CryptMemFree(name);
1721     }
1722     len = CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
1723      NULL, 0);
1724     name = CryptMemAlloc(len * sizeof(WCHAR));
1725     if (name)
1726     {
1727         CertGetNameStringW(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
1728          name, len);
1729         TRACE_(chain)("issued to %s\n", debugstr_w(name));
1730         CryptMemFree(name);
1731     }
1732     TRACE_(chain)("valid from %s to %s\n",
1733      filetime_to_str(&cert->pCertInfo->NotBefore),
1734      filetime_to_str(&cert->pCertInfo->NotAfter));
1735     TRACE_(chain)("%d extensions\n", cert->pCertInfo->cExtension);
1736     for (i = 0; i < cert->pCertInfo->cExtension; i++)
1737         dump_extension(&cert->pCertInfo->rgExtension[i]);
1738 }
1739 
1740 static BOOL CRYPT_KeyUsageValid(CertificateChainEngine *engine,
1741  PCCERT_CONTEXT cert, BOOL isRoot, BOOL isCA, DWORD index)
1742 {
1743     PCERT_EXTENSION ext;
1744     BOOL ret;
1745     BYTE usageBits = 0;
1746 
1747     ext = CertFindExtension(szOID_KEY_USAGE, cert->pCertInfo->cExtension,
1748      cert->pCertInfo->rgExtension);
1749     if (ext)
1750     {
1751         CRYPT_BIT_BLOB usage;
1752         DWORD size = sizeof(usage);
1753 
1754         ret = CryptDecodeObjectEx(cert->dwCertEncodingType, X509_BITS,
1755          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
1756          &usage, &size);
1757         if (!ret)
1758             return FALSE;
1759         else if (usage.cbData > 2)
1760         {
1761             /* The key usage extension only defines 9 bits => no more than 2
1762              * bytes are needed to encode all known usages.
1763              */
1764             return FALSE;
1765         }
1766         else
1767         {
1768             /* The only bit relevant to chain validation is the keyCertSign
1769              * bit, which is always in the least significant byte of the
1770              * key usage bits.
1771              */
1772             usageBits = usage.pbData[usage.cbData - 1];
1773         }
1774     }
1775     if (isCA)
1776     {
1777         if (!ext)
1778         {
1779             /* MS appears to violate RFC 5280, section 4.2.1.3 (Key Usage)
1780              * here.  Quoting the RFC:
1781              * "This [key usage] extension MUST appear in certificates that
1782              * contain public keys that are used to validate digital signatures
1783              * on other public key certificates or CRLs."
1784              * MS appears to accept certs that do not contain key usage
1785              * extensions as CA certs.  V1 and V2 certificates did not have
1786              * extensions, and many root certificates are V1 certificates, so
1787              * perhaps this is prudent.  On the other hand, MS also accepts V3
1788              * certs without key usage extensions.  Because some CAs, e.g.
1789              * Certum, also do not include key usage extensions in their
1790              * intermediate certificates, we are forced to accept V3
1791              * certificates without key usage extensions as well.
1792              */
1793             ret = TRUE;
1794         }
1795         else
1796         {
1797             if (!(usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE))
1798             {
1799                 WARN_(chain)("keyCertSign not asserted on a CA cert\n");
1800                 ret = FALSE;
1801             }
1802             else
1803                 ret = TRUE;
1804         }
1805     }
1806     else
1807     {
1808         if (ext && (usageBits & CERT_KEY_CERT_SIGN_KEY_USAGE))
1809         {
1810             WARN_(chain)("keyCertSign asserted on a non-CA cert\n");
1811             ret = FALSE;
1812         }
1813         else
1814             ret = TRUE;
1815     }
1816     return ret;
1817 }
1818 
1819 static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
1820 {
1821     BOOL ret = TRUE;
1822     DWORD i;
1823 
1824     for (i = 0; ret && i < cert->pCertInfo->cExtension; i++)
1825     {
1826         if (cert->pCertInfo->rgExtension[i].fCritical)
1827         {
1828             LPCSTR oid = cert->pCertInfo->rgExtension[i].pszObjId;
1829 
1830             if (!strcmp(oid, szOID_BASIC_CONSTRAINTS))
1831                 ret = TRUE;
1832             else if (!strcmp(oid, szOID_BASIC_CONSTRAINTS2))
1833                 ret = TRUE;
1834             else if (!strcmp(oid, szOID_NAME_CONSTRAINTS))
1835                 ret = TRUE;
1836             else if (!strcmp(oid, szOID_KEY_USAGE))
1837                 ret = TRUE;
1838             else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME))
1839                 ret = TRUE;
1840             else if (!strcmp(oid, szOID_SUBJECT_ALT_NAME2))
1841                 ret = TRUE;
1842             else if (!strcmp(oid, szOID_CERT_POLICIES))
1843                 ret = TRUE;
1844             else if (!strcmp(oid, szOID_ENHANCED_KEY_USAGE))
1845                 ret = TRUE;
1846             else
1847             {
1848                 FIXME("unsupported critical extension %s\n",
1849                  debugstr_a(oid));
1850                 ret = FALSE;
1851             }
1852         }
1853     }
1854     return ret;
1855 }
1856 
1857 static BOOL CRYPT_IsCertVersionValid(PCCERT_CONTEXT cert)
1858 {
1859     BOOL ret = TRUE;
1860 
1861     /* Checks whether the contents of the cert match the cert's version. */
1862     switch (cert->pCertInfo->dwVersion)
1863     {
1864     case CERT_V1:
1865         /* A V1 cert may not contain unique identifiers.  See RFC 5280,
1866          * section 4.1.2.8:
1867          * "These fields MUST only appear if the version is 2 or 3 (Section
1868          *  4.1.2.1).  These fields MUST NOT appear if the version is 1."
1869          */
1870         if (cert->pCertInfo->IssuerUniqueId.cbData ||
1871          cert->pCertInfo->SubjectUniqueId.cbData)
1872             ret = FALSE;
1873         /* A V1 cert may not contain extensions.  See RFC 5280, section 4.1.2.9:
1874          * "This field MUST only appear if the version is 3 (Section 4.1.2.1)."
1875          */
1876         if (cert->pCertInfo->cExtension)
1877             ret = FALSE;
1878         break;
1879     case CERT_V2:
1880         /* A V2 cert may not contain extensions.  See RFC 5280, section 4.1.2.9:
1881          * "This field MUST only appear if the version is 3 (Section 4.1.2.1)."
1882          */
1883         if (cert->pCertInfo->cExtension)
1884             ret = FALSE;
1885         break;
1886     case CERT_V3:
1887         /* Do nothing, all fields are allowed for V3 certs */
1888         break;
1889     default:
1890         WARN_(chain)("invalid cert version %d\n", cert->pCertInfo->dwVersion);
1891         ret = FALSE;
1892     }
1893     return ret;
1894 }
1895 
1896 static void CRYPT_CheckSimpleChain(CertificateChainEngine *engine,
1897  PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
1898 {
1899     PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1];
1900     int i;
1901     BOOL pathLengthConstraintViolated = FALSE;
1902     CERT_BASIC_CONSTRAINTS2_INFO constraints = { FALSE, FALSE, 0 };
1903     DWORD type;
1904 
1905     TRACE_(chain)("checking chain with %d elements for time %s\n",
1906      chain->cElement, filetime_to_str(time));
1907     for (i = chain->cElement - 1; i >= 0; i--)
1908     {
1909         BOOL isRoot;
1910 
1911         if (TRACE_ON(chain))
1912             dump_element(chain->rgpElement[i]->pCertContext);
1913         if (i == chain->cElement - 1)
1914             isRoot = CRYPT_IsCertificateSelfSigned(
1915              chain->rgpElement[i]->pCertContext, NULL);
1916         else
1917             isRoot = FALSE;
1918         if (!CRYPT_IsCertVersionValid(chain->rgpElement[i]->pCertContext))
1919         {
1920             /* MS appears to accept certs whose versions don't match their
1921              * contents, so there isn't an appropriate error code.
1922              */
1923             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1924              CERT_TRUST_INVALID_EXTENSION;
1925         }
1926         if (CertVerifyTimeValidity(time,
1927          chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
1928             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1929              CERT_TRUST_IS_NOT_TIME_VALID;
1930         if (i != 0)
1931         {
1932             /* Check the signature of the cert this issued */
1933             if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
1934              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
1935              (void *)chain->rgpElement[i - 1]->pCertContext,
1936              CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
1937              (void *)chain->rgpElement[i]->pCertContext, 0, NULL))
1938                 chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |=
1939                  CERT_TRUST_IS_NOT_SIGNATURE_VALID;
1940             /* Once a path length constraint has been violated, every remaining
1941              * CA cert's basic constraints is considered invalid.
1942              */
1943             if (pathLengthConstraintViolated)
1944                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1945                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
1946             else if (!CRYPT_CheckBasicConstraintsForCA(engine,
1947              chain->rgpElement[i]->pCertContext, &constraints, i - 1, isRoot,
1948              &pathLengthConstraintViolated))
1949                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1950                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
1951             else if (constraints.fPathLenConstraint &&
1952              constraints.dwPathLenConstraint)
1953             {
1954                 /* This one's valid - decrement max length */
1955                 constraints.dwPathLenConstraint--;
1956             }
1957         }
1958         else
1959         {
1960             /* Check whether end cert has a basic constraints extension */
1961             if (!CRYPT_DecodeBasicConstraints(
1962              chain->rgpElement[i]->pCertContext, &constraints, FALSE))
1963                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1964                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
1965         }
1966         if (!CRYPT_KeyUsageValid(engine, chain->rgpElement[i]->pCertContext,
1967          isRoot, constraints.fCA, i))
1968             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1969              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
1970         if (CRYPT_IsSimpleChainCyclic(chain))
1971         {
1972             /* If the chain is cyclic, then the path length constraints
1973              * are violated, because the chain is infinitely long.
1974              */
1975             pathLengthConstraintViolated = TRUE;
1976             chain->TrustStatus.dwErrorStatus |=
1977              CERT_TRUST_IS_PARTIAL_CHAIN |
1978              CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
1979         }
1980         /* Check whether every critical extension is supported */
1981         if (!CRYPT_CriticalExtensionsSupported(
1982          chain->rgpElement[i]->pCertContext))
1983             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
1984              CERT_TRUST_INVALID_EXTENSION |
1985              CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT;
1986         CRYPT_CombineTrustStatus(&chain->TrustStatus,
1987          &chain->rgpElement[i]->TrustStatus);
1988     }
1989     CRYPT_CheckChainNameConstraints(chain);
1990     CRYPT_CheckChainPolicies(chain);
1991     if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext, &type))
1992     {
1993         rootElement->TrustStatus.dwInfoStatus |=
1994          CERT_TRUST_IS_SELF_SIGNED | type;
1995         CRYPT_CheckRootCert(engine->hRoot, rootElement);
1996     }
1997     CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
1998 }
1999 
2000 static PCCERT_CONTEXT CRYPT_FindIssuer(const CertificateChainEngine *engine, const CERT_CONTEXT *cert,
2001         HCERTSTORE store, DWORD type, void *para, DWORD flags, PCCERT_CONTEXT prev_issuer)
2002 {
2003     CRYPT_URL_ARRAY *urls;
2004     PCCERT_CONTEXT issuer;
2005     DWORD size;
2006     BOOL res;
2007 
2008     issuer = CertFindCertificateInStore(store, cert->dwCertEncodingType, 0, type, para, prev_issuer);
2009     if(issuer) {
2010         TRACE("Found in store %p\n", issuer);
2011         return issuer;
2012     }
2013 
2014     /* FIXME: For alternate issuers, we don't search world store nor try to retrieve issuer from URL.
2015      * This needs more tests.
2016      */
2017     if(prev_issuer)
2018         return NULL;
2019 
2020     if(engine->hWorld) {
2021         issuer = CertFindCertificateInStore(engine->hWorld, cert->dwCertEncodingType, 0, type, para, NULL);
2022         if(issuer) {
2023             TRACE("Found in world %p\n", issuer);
2024             return issuer;
2025         }
2026     }
2027 
2028     res = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void*)cert, 0, NULL, &size, NULL, NULL, NULL);
2029     if(!res)
2030         return NULL;
2031 
2032     urls = HeapAlloc(GetProcessHeap(), 0, size);
2033     if(!urls)
2034         return NULL;
2035 
2036     res = CryptGetObjectUrl(URL_OID_CERTIFICATE_ISSUER, (void*)cert, 0, urls, &size, NULL, NULL, NULL);
2037     if(res)
2038     {
2039         CERT_CONTEXT *new_cert;
2040         HCERTSTORE new_store;
2041         unsigned i;
2042 
2043         for(i=0; i < urls->cUrl; i++)
2044         {
2045             TRACE("Trying URL %s\n", debugstr_w(urls->rgwszUrl[i]));
2046 
2047             res = CryptRetrieveObjectByUrlW(urls->rgwszUrl[i], CONTEXT_OID_CERTIFICATE,
2048              (flags & CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL) ? CRYPT_CACHE_ONLY_RETRIEVAL : CRYPT_AIA_RETRIEVAL,
2049              0, (void**)&new_cert, NULL, NULL, NULL, NULL);
2050             if(!res)
2051             {
2052                 TRACE("CryptRetrieveObjectByUrlW failed: %u\n", GetLastError());
2053                 continue;
2054             }
2055 
2056             /* FIXME: Use new_cert->hCertStore once cert ref count bug is fixed. */
2057             new_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
2058             CertAddCertificateContextToStore(new_store, new_cert, CERT_STORE_ADD_NEW, NULL);
2059             issuer = CertFindCertificateInStore(new_store, cert->dwCertEncodingType, 0, type, para, NULL);
2060             CertFreeCertificateContext(new_cert);
2061             CertCloseStore(new_store, 0);
2062             if(issuer)
2063             {
2064                 TRACE("Found downloaded issuer %p\n", issuer);
2065                 break;
2066             }
2067         }
2068     }
2069 
2070     HeapFree(GetProcessHeap(), 0, urls);
2071     return issuer;
2072 }
2073 
2074 static PCCERT_CONTEXT CRYPT_GetIssuer(const CertificateChainEngine *engine,
2075         HCERTSTORE store, PCCERT_CONTEXT subject, PCCERT_CONTEXT prevIssuer,
2076         DWORD flags, DWORD *infoStatus)
2077 {
2078     PCCERT_CONTEXT issuer = NULL;
2079     PCERT_EXTENSION ext;
2080     DWORD size;
2081 
2082     *infoStatus = 0;
2083     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
2084      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
2085     {
2086         CERT_AUTHORITY_KEY_ID_INFO *info;
2087         BOOL ret;
2088 
2089         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
2090          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
2091          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2092          &info, &size);
2093         if (ret)
2094         {
2095             CERT_ID id;
2096 
2097             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
2098             {
2099                 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
2100                 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
2101                  sizeof(CERT_NAME_BLOB));
2102                 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
2103                  &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
2104 
2105                 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer);
2106                 if (issuer)
2107                 {
2108                     TRACE_(chain)("issuer found by issuer/serial number\n");
2109                     *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
2110                 }
2111             }
2112             else if (info->KeyId.cbData)
2113             {
2114                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
2115 
2116                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
2117                 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer);
2118                 if (issuer)
2119                 {
2120                     TRACE_(chain)("issuer found by key id\n");
2121                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
2122                 }
2123             }
2124             LocalFree(info);
2125         }
2126     }
2127     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
2128      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
2129     {
2130         CERT_AUTHORITY_KEY_ID2_INFO *info;
2131         BOOL ret;
2132 
2133         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
2134          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
2135          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2136          &info, &size);
2137         if (ret)
2138         {
2139             CERT_ID id;
2140 
2141             if (info->AuthorityCertIssuer.cAltEntry &&
2142              info->AuthorityCertSerialNumber.cbData)
2143             {
2144                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
2145                 DWORD i;
2146 
2147                 for (i = 0; !directoryName &&
2148                  i < info->AuthorityCertIssuer.cAltEntry; i++)
2149                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
2150                      == CERT_ALT_NAME_DIRECTORY_NAME)
2151                         directoryName =
2152                          &info->AuthorityCertIssuer.rgAltEntry[i];
2153                 if (directoryName)
2154                 {
2155                     id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
2156                     memcpy(&id.u.IssuerSerialNumber.Issuer,
2157                      &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
2158                     memcpy(&id.u.IssuerSerialNumber.SerialNumber,
2159                      &info->AuthorityCertSerialNumber,
2160                      sizeof(CRYPT_INTEGER_BLOB));
2161 
2162                     issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer);
2163                     if (issuer)
2164                     {
2165                         TRACE_(chain)("issuer found by directory name\n");
2166                         *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
2167                     }
2168                 }
2169                 else
2170                     FIXME("no supported name type in authority key id2\n");
2171             }
2172             else if (info->KeyId.cbData)
2173             {
2174                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
2175                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
2176                 issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_CERT_ID, &id, flags, prevIssuer);
2177                 if (issuer)
2178                 {
2179                     TRACE_(chain)("issuer found by key id\n");
2180                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
2181                 }
2182             }
2183             LocalFree(info);
2184         }
2185     }
2186     else
2187     {
2188         issuer = CRYPT_FindIssuer(engine, subject, store, CERT_FIND_SUBJECT_NAME,
2189          &subject->pCertInfo->Issuer, flags, prevIssuer);
2190         TRACE_(chain)("issuer found by name\n");
2191         *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
2192     }
2193     return issuer;
2194 }
2195 
2196 /* Builds a simple chain by finding an issuer for the last cert in the chain,
2197  * until reaching a self-signed cert, or until no issuer can be found.
2198  */
2199 static BOOL CRYPT_BuildSimpleChain(const CertificateChainEngine *engine,
2200  HCERTSTORE world, DWORD flags, PCERT_SIMPLE_CHAIN chain)
2201 {
2202     BOOL ret = TRUE;
2203     PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext;
2204 
2205     while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
2206      !CRYPT_IsCertificateSelfSigned(cert, NULL))
2207     {
2208         PCCERT_CONTEXT issuer = CRYPT_GetIssuer(engine, world, cert, NULL, flags,
2209          &chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
2210 
2211         if (issuer)
2212         {
2213             ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer,
2214              chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
2215             /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to
2216              * close the enumeration that found it
2217              */
2218             CertFreeCertificateContext(issuer);
2219             cert = issuer;
2220         }
2221         else
2222         {
2223             TRACE_(chain)("Couldn't find issuer, halting chain creation\n");
2224             chain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN;
2225             break;
2226         }
2227     }
2228     return ret;
2229 }
2230 
2231 static LPCSTR debugstr_filetime(LPFILETIME pTime)
2232 {
2233     if (!pTime)
2234         return "(nil)";
2235     return wine_dbg_sprintf("%p (%s)", pTime, filetime_to_str(pTime));
2236 }
2237 
2238 static BOOL CRYPT_GetSimpleChainForCert(CertificateChainEngine *engine,
2239  HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime, DWORD flags,
2240  PCERT_SIMPLE_CHAIN *ppChain)
2241 {
2242     BOOL ret = FALSE;
2243     PCERT_SIMPLE_CHAIN chain;
2244 
2245     TRACE("(%p, %p, %p, %s)\n", engine, world, cert, debugstr_filetime(pTime));
2246 
2247     chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
2248     if (chain)
2249     {
2250         memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
2251         chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
2252         ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
2253         if (ret)
2254         {
2255             ret = CRYPT_BuildSimpleChain(engine, world, flags, chain);
2256             if (ret)
2257                 CRYPT_CheckSimpleChain(engine, chain, pTime);
2258         }
2259         if (!ret)
2260         {
2261             CRYPT_FreeSimpleChain(chain);
2262             chain = NULL;
2263         }
2264         *ppChain = chain;
2265     }
2266     return ret;
2267 }
2268 
2269 static BOOL CRYPT_BuildCandidateChainFromCert(CertificateChainEngine *engine,
2270  PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore, DWORD flags,
2271  CertificateChain **ppChain)
2272 {
2273     PCERT_SIMPLE_CHAIN simpleChain = NULL;
2274     HCERTSTORE world;
2275     BOOL ret;
2276 
2277     world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
2278      CERT_STORE_CREATE_NEW_FLAG, NULL);
2279     CertAddStoreToCollection(world, engine->hWorld, 0, 0);
2280     if (hAdditionalStore)
2281         CertAddStoreToCollection(world, hAdditionalStore, 0, 0);
2282     /* FIXME: only simple chains are supported for now, as CTLs aren't
2283      * supported yet.
2284      */
2285     if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime, flags, &simpleChain)))
2286     {
2287         CertificateChain *chain = CryptMemAlloc(sizeof(CertificateChain));
2288 
2289         if (chain)
2290         {
2291             chain->ref = 1;
2292             chain->world = world;
2293             chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
2294             chain->context.TrustStatus = simpleChain->TrustStatus;
2295             chain->context.cChain = 1;
2296             chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN));
2297             chain->context.rgpChain[0] = simpleChain;
2298             chain->context.cLowerQualityChainContext = 0;
2299             chain->context.rgpLowerQualityChainContext = NULL;
2300             chain->context.fHasRevocationFreshnessTime = FALSE;
2301             chain->context.dwRevocationFreshnessTime = 0;
2302         }
2303         else
2304         {
2305             CRYPT_FreeSimpleChain(simpleChain);
2306             ret = FALSE;
2307         }
2308         *ppChain = chain;
2309     }
2310     return ret;
2311 }
2312 
2313 /* Makes and returns a copy of chain, up to and including element iElement. */
2314 static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement(
2315  const CERT_SIMPLE_CHAIN *chain, DWORD iElement)
2316 {
2317     PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
2318 
2319     if (copy)
2320     {
2321         memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN));
2322         copy->cbSize = sizeof(CERT_SIMPLE_CHAIN);
2323         copy->rgpElement =
2324          CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
2325         if (copy->rgpElement)
2326         {
2327             DWORD i;
2328             BOOL ret = TRUE;
2329 
2330             memset(copy->rgpElement, 0,
2331              (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
2332             for (i = 0; ret && i <= iElement; i++)
2333             {
2334                 PCERT_CHAIN_ELEMENT element =
2335                  CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
2336 
2337                 if (element)
2338                 {
2339                     *element = *chain->rgpElement[i];
2340                     element->pCertContext = CertDuplicateCertificateContext(
2341                      chain->rgpElement[i]->pCertContext);
2342                     /* Reset the trust status of the copied element, it'll get
2343                      * rechecked after the new chain is done.
2344                      */
2345                     memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
2346                     copy->rgpElement[copy->cElement++] = element;
2347                 }
2348                 else
2349                     ret = FALSE;
2350             }
2351             if (!ret)
2352             {
2353                 for (i = 0; i <= iElement; i++)
2354                     CryptMemFree(copy->rgpElement[i]);
2355                 CryptMemFree(copy->rgpElement);
2356                 CryptMemFree(copy);
2357                 copy = NULL;
2358             }
2359         }
2360         else
2361         {
2362             CryptMemFree(copy);
2363             copy = NULL;
2364         }
2365     }
2366     return copy;
2367 }
2368 
2369 static void CRYPT_FreeLowerQualityChains(CertificateChain *chain)
2370 {
2371     DWORD i;
2372 
2373     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
2374         CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]);
2375     CryptMemFree(chain->context.rgpLowerQualityChainContext);
2376     chain->context.cLowerQualityChainContext = 0;
2377     chain->context.rgpLowerQualityChainContext = NULL;
2378 }
2379 
2380 static void CRYPT_FreeChainContext(CertificateChain *chain)
2381 {
2382     DWORD i;
2383 
2384     CRYPT_FreeLowerQualityChains(chain);
2385     for (i = 0; i < chain->context.cChain; i++)
2386         CRYPT_FreeSimpleChain(chain->context.rgpChain[i]);
2387     CryptMemFree(chain->context.rgpChain);
2388     CertCloseStore(chain->world, 0);
2389     CryptMemFree(chain);
2390 }
2391 
2392 /* Makes and returns a copy of chain, up to and including element iElement of
2393  * simple chain iChain.
2394  */
2395 static CertificateChain *CRYPT_CopyChainToElement(CertificateChain *chain,
2396  DWORD iChain, DWORD iElement)
2397 {
2398     CertificateChain *copy = CryptMemAlloc(sizeof(CertificateChain));
2399 
2400     if (copy)
2401     {
2402         copy->ref = 1;
2403         copy->world = CertDuplicateStore(chain->world);
2404         copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
2405         /* Leave the trust status of the copied chain unset, it'll get
2406          * rechecked after the new chain is done.
2407          */
2408         memset(&copy->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
2409         copy->context.cLowerQualityChainContext = 0;
2410         copy->context.rgpLowerQualityChainContext = NULL;
2411         copy->context.fHasRevocationFreshnessTime = FALSE;
2412         copy->context.dwRevocationFreshnessTime = 0;
2413         copy->context.rgpChain = CryptMemAlloc(
2414          (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
2415         if (copy->context.rgpChain)
2416         {
2417             BOOL ret = TRUE;
2418             DWORD i;
2419 
2420             memset(copy->context.rgpChain, 0,
2421              (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
2422             if (iChain)
2423             {
2424                 for (i = 0; ret && iChain && i < iChain - 1; i++)
2425                 {
2426                     copy->context.rgpChain[i] =
2427                      CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
2428                      chain->context.rgpChain[i]->cElement - 1);
2429                     if (!copy->context.rgpChain[i])
2430                         ret = FALSE;
2431                 }
2432             }
2433             else
2434                 i = 0;
2435             if (ret)
2436             {
2437                 copy->context.rgpChain[i] =
2438                  CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
2439                  iElement);
2440                 if (!copy->context.rgpChain[i])
2441                     ret = FALSE;
2442             }
2443             if (!ret)
2444             {
2445                 CRYPT_FreeChainContext(copy);
2446                 copy = NULL;
2447             }
2448             else
2449                 copy->context.cChain = iChain + 1;
2450         }
2451         else
2452         {
2453             CryptMemFree(copy);
2454             copy = NULL;
2455         }
2456     }
2457     return copy;
2458 }
2459 
2460 static CertificateChain *CRYPT_BuildAlternateContextFromChain(
2461  CertificateChainEngine *engine, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
2462  DWORD flags, CertificateChain *chain)
2463 {
2464     CertificateChain *alternate;
2465 
2466     TRACE("(%p, %s, %p, %p)\n", engine, debugstr_filetime(pTime),
2467      hAdditionalStore, chain);
2468 
2469     /* Always start with the last "lower quality" chain to ensure a consistent
2470      * order of alternate creation:
2471      */
2472     if (chain->context.cLowerQualityChainContext)
2473         chain = (CertificateChain*)chain->context.rgpLowerQualityChainContext[
2474          chain->context.cLowerQualityChainContext - 1];
2475     /* A chain with only one element can't have any alternates */
2476     if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1)
2477         alternate = NULL;
2478     else
2479     {
2480         DWORD i, j, infoStatus;
2481         PCCERT_CONTEXT alternateIssuer = NULL;
2482 
2483         alternate = NULL;
2484         for (i = 0; !alternateIssuer && i < chain->context.cChain; i++)
2485             for (j = 0; !alternateIssuer &&
2486              j < chain->context.rgpChain[i]->cElement - 1; j++)
2487             {
2488                 PCCERT_CONTEXT subject =
2489                  chain->context.rgpChain[i]->rgpElement[j]->pCertContext;
2490                 PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext(
2491                  chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext);
2492 
2493                 alternateIssuer = CRYPT_GetIssuer(engine, prevIssuer->hCertStore,
2494                  subject, prevIssuer, flags, &infoStatus);
2495             }
2496         if (alternateIssuer)
2497         {
2498             i--;
2499             j--;
2500             alternate = CRYPT_CopyChainToElement(chain, i, j);
2501             if (alternate)
2502             {
2503                 BOOL ret = CRYPT_AddCertToSimpleChain(engine,
2504                  alternate->context.rgpChain[i], alternateIssuer, infoStatus);
2505 
2506                 /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it
2507                  * to close the enumeration that found it
2508                  */
2509                 CertFreeCertificateContext(alternateIssuer);
2510                 if (ret)
2511                 {
2512                     ret = CRYPT_BuildSimpleChain(engine, alternate->world,
2513                      flags, alternate->context.rgpChain[i]);
2514                     if (ret)
2515                         CRYPT_CheckSimpleChain(engine,
2516                          alternate->context.rgpChain[i], pTime);
2517                     CRYPT_CombineTrustStatus(&alternate->context.TrustStatus,
2518                      &alternate->context.rgpChain[i]->TrustStatus);
2519                 }
2520                 if (!ret)
2521                 {
2522                     CRYPT_FreeChainContext(alternate);
2523                     alternate = NULL;
2524                 }
2525             }
2526         }
2527     }
2528     TRACE("%p\n", alternate);
2529     return alternate;
2530 }
2531 
2532 #define CHAIN_QUALITY_SIGNATURE_VALID   0x16
2533 #define CHAIN_QUALITY_TIME_VALID        8
2534 #define CHAIN_QUALITY_COMPLETE_CHAIN    4
2535 #define CHAIN_QUALITY_BASIC_CONSTRAINTS 2
2536 #define CHAIN_QUALITY_TRUSTED_ROOT      1
2537 
2538 #define CHAIN_QUALITY_HIGHEST \
2539  CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
2540  CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_BASIC_CONSTRAINTS | \
2541  CHAIN_QUALITY_TRUSTED_ROOT
2542 
2543 #define IS_TRUST_ERROR_SET(TrustStatus, bits) \
2544  (TrustStatus)->dwErrorStatus & (bits)
2545 
2546 static DWORD CRYPT_ChainQuality(const CertificateChain *chain)
2547 {
2548     DWORD quality = CHAIN_QUALITY_HIGHEST;
2549 
2550     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
2551      CERT_TRUST_IS_UNTRUSTED_ROOT))
2552         quality &= ~CHAIN_QUALITY_TRUSTED_ROOT;
2553     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
2554      CERT_TRUST_INVALID_BASIC_CONSTRAINTS))
2555         quality &= ~CHAIN_QUALITY_BASIC_CONSTRAINTS;
2556     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
2557      CERT_TRUST_IS_PARTIAL_CHAIN))
2558         quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN;
2559     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
2560      CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED))
2561         quality &= ~CHAIN_QUALITY_TIME_VALID;
2562     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
2563      CERT_TRUST_IS_NOT_SIGNATURE_VALID))
2564         quality &= ~CHAIN_QUALITY_SIGNATURE_VALID;
2565     return quality;
2566 }
2567 
2568 /* Chooses the highest quality chain among chain and its "lower quality"
2569  * alternate chains.  Returns the highest quality chain, with all other
2570  * chains as lower quality chains of it.
2571  */
2572 static CertificateChain *CRYPT_ChooseHighestQualityChain(
2573  CertificateChain *chain)
2574 {
2575     DWORD i;
2576 
2577     /* There are always only two chains being considered:  chain, and an
2578      * alternate at chain->rgpLowerQualityChainContext[i].  If the alternate
2579      * has a higher quality than chain, the alternate gets assigned the lower
2580      * quality contexts, with chain taking the alternate's place among the
2581      * lower quality contexts.
2582      */
2583     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
2584     {
2585         CertificateChain *alternate =
2586          (CertificateChain*)chain->context.rgpLowerQualityChainContext[i];
2587 
2588         if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain))
2589         {
2590             alternate->context.cLowerQualityChainContext =
2591              chain->context.cLowerQualityChainContext;
2592             alternate->context.rgpLowerQualityChainContext =
2593              chain->context.rgpLowerQualityChainContext;
2594             alternate->context.rgpLowerQualityChainContext[i] =
2595              (PCCERT_CHAIN_CONTEXT)chain;
2596             chain->context.cLowerQualityChainContext = 0;
2597             chain->context.rgpLowerQualityChainContext = NULL;
2598             chain = alternate;
2599         }
2600     }
2601     return chain;
2602 }
2603 
2604 static BOOL CRYPT_AddAlternateChainToChain(CertificateChain *chain,
2605  const CertificateChain *alternate)
2606 {
2607     BOOL ret;
2608 
2609     if (chain->context.cLowerQualityChainContext)
2610         chain->context.rgpLowerQualityChainContext =
2611          CryptMemRealloc(chain->context.rgpLowerQualityChainContext,
2612          (chain->context.cLowerQualityChainContext + 1) *
2613          sizeof(PCCERT_CHAIN_CONTEXT));
2614     else
2615         chain->context.rgpLowerQualityChainContext =
2616          CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT));
2617     if (chain->context.rgpLowerQualityChainContext)
2618     {
2619         chain->context.rgpLowerQualityChainContext[
2620          chain->context.cLowerQualityChainContext++] =
2621          (PCCERT_CHAIN_CONTEXT)alternate;
2622         ret = TRUE;
2623     }
2624     else
2625         ret = FALSE;
2626     return ret;
2627 }
2628 
2629 static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain(
2630  const CERT_CHAIN_CONTEXT *chain, DWORD i)
2631 {
2632     DWORD j, iElement;
2633     PCERT_CHAIN_ELEMENT element = NULL;
2634 
2635     for (j = 0, iElement = 0; !element && j < chain->cChain; j++)
2636     {
2637         if (iElement + chain->rgpChain[j]->cElement < i)
2638             iElement += chain->rgpChain[j]->cElement;
2639         else
2640             element = chain->rgpChain[j]->rgpElement[i - iElement];
2641     }
2642     return element;
2643 }
2644 
2645 typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS {
2646     DWORD            cbSize;
2647     CERT_USAGE_MATCH RequestedUsage;
2648 } CERT_CHAIN_PARA_NO_EXTRA_FIELDS;
2649 
2650 static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
2651  LPFILETIME pTime, HCERTSTORE hAdditionalStore,
2652  const CERT_CHAIN_PARA *pChainPara, DWORD chainFlags)
2653 {
2654     DWORD cContext;
2655 
2656     if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT)
2657         cContext = 1;
2658     else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) ||
2659      (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT))
2660     {
2661         DWORD i;
2662 
2663         for (i = 0, cContext = 0; i < chain->cChain; i++)
2664         {
2665             if (i < chain->cChain - 1 ||
2666              chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN)
2667                 cContext += chain->rgpChain[i]->cElement;
2668             else
2669                 cContext += chain->rgpChain[i]->cElement - 1;
2670         }
2671     }
2672     else
2673         cContext = 0;
2674     if (cContext)
2675     {
2676         DWORD i, j, iContext, revocationFlags;
2677         CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 };
2678         CERT_REVOCATION_STATUS revocationStatus =
2679          { sizeof(revocationStatus), 0 };
2680         BOOL ret;
2681 
2682         revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG;
2683         if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY)
2684             revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION;
2685         if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT)
2686             revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG;
2687         revocationPara.pftTimeToUse = pTime;
2688         if (hAdditionalStore)
2689         {
2690             revocationPara.cCertStore = 1;
2691             revocationPara.rgCertStore = &hAdditionalStore;
2692             revocationPara.hCrlStore = hAdditionalStore;
2693         }
2694         if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA))
2695         {
2696             revocationPara.dwUrlRetrievalTimeout =
2697              pChainPara->dwUrlRetrievalTimeout;
2698             revocationPara.fCheckFreshnessTime =
2699              pChainPara->fCheckRevocationFreshnessTime;
2700             revocationPara.dwFreshnessTime =
2701              pChainPara->dwRevocationFreshnessTime;
2702         }
2703         for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain; i++)
2704         {
2705             for (j = 0; iContext < cContext &&
2706              j < chain->rgpChain[i]->cElement; j++, iContext++)
2707             {
2708                 PCCERT_CONTEXT certToCheck =
2709                  chain->rgpChain[i]->rgpElement[j]->pCertContext;
2710 
2711                 if (j < chain->rgpChain[i]->cElement - 1)
2712                     revocationPara.pIssuerCert =
2713                      chain->rgpChain[i]->rgpElement[j + 1]->pCertContext;
2714                 else
2715                     revocationPara.pIssuerCert = certToCheck;
2716 
2717                 ret = CertVerifyRevocation(X509_ASN_ENCODING,
2718                  CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certToCheck,
2719                  revocationFlags, &revocationPara, &revocationStatus);
2720 
2721                 if (!ret && revocationStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK &&
2722                     revocationPara.pIssuerCert == certToCheck)
2723                 {
2724                     FIXME("Unable to find CRL for CA certificate\n");
2725                     ret = TRUE;
2726                     revocationStatus.dwError = 0;
2727                 }
2728 
2729                 if (!ret)
2730                 {
2731                     PCERT_CHAIN_ELEMENT element = CRYPT_FindIthElementInChain(
2732                      chain, iContext);
2733                     DWORD error;
2734 
2735                     switch (revocationStatus.dwError)
2736                     {
2737                     case CRYPT_E_NO_REVOCATION_CHECK:
2738                     case CRYPT_E_NO_REVOCATION_DLL:
2739                     case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
2740                         /* If the revocation status is unknown, it's assumed
2741                          * to be offline too.
2742                          */
2743                         error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
2744                          CERT_TRUST_IS_OFFLINE_REVOCATION;
2745                         break;
2746                     case CRYPT_E_REVOCATION_OFFLINE:
2747                         error = CERT_TRUST_IS_OFFLINE_REVOCATION;
2748                         break;
2749                     case CRYPT_E_REVOKED:
2750                         error = CERT_TRUST_IS_REVOKED;
2751                         break;
2752                     default:
2753                         WARN("unmapped error %08x\n", revocationStatus.dwError);
2754                         error = 0;
2755                     }
2756                     if (element)
2757                     {
2758                         /* FIXME: set element's pRevocationInfo member */
2759                         element->TrustStatus.dwErrorStatus |= error;
2760                     }
2761                     chain->TrustStatus.dwErrorStatus |= error;
2762                 }
2763             }
2764         }
2765     }
2766 }
2767 
2768 static void CRYPT_CheckUsages(PCERT_CHAIN_CONTEXT chain,
2769  const CERT_CHAIN_PARA *pChainPara)
2770 {
2771     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) &&
2772      pChainPara->RequestedUsage.Usage.cUsageIdentifier)
2773     {
2774         PCCERT_CONTEXT endCert;
2775         PCERT_EXTENSION ext;
2776         BOOL validForUsage;
2777 
2778         /* A chain, if created, always includes the end certificate */
2779         endCert = chain->rgpChain[0]->rgpElement[0]->pCertContext;
2780         /* The extended key usage extension specifies how a certificate's
2781          * public key may be used.  From RFC 5280, section 4.2.1.12:
2782          * "This extension indicates one or more purposes for which the
2783          *  certified public key may be used, in addition to or in place of the
2784          *  basic purposes indicated in the key usage extension."
2785          * If the extension is present, it only satisfies the requested usage
2786          * if that usage is included in the extension:
2787          * "If the extension is present, then the certificate MUST only be used
2788          *  for one of the purposes indicated."
2789          * There is also the special anyExtendedKeyUsage OID, but it doesn't
2790          * have to be respected:
2791          * "Applications that require the presence of a particular purpose
2792          *  MAY reject certificates that include the anyExtendedKeyUsage OID
2793          *  but not the particular OID expected for the application."
2794          * For now, I'm being more conservative and ignoring the presence of
2795          * the anyExtendedKeyUsage OID.
2796          */
2797         if ((ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2798          endCert->pCertInfo->cExtension, endCert->pCertInfo->rgExtension)))
2799         {
2800             const CERT_ENHKEY_USAGE *requestedUsage =
2801              &pChainPara->RequestedUsage.Usage;
2802             CERT_ENHKEY_USAGE *usage;
2803             DWORD size;
2804 
2805             if (CryptDecodeObjectEx(X509_ASN_ENCODING,
2806              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2807              CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size))
2808             {
2809                 if (pChainPara->RequestedUsage.dwType == USAGE_MATCH_TYPE_AND)
2810                 {
2811                     DWORD i, j;
2812 
2813                     /* For AND matches, all usages must be present */
2814                     validForUsage = TRUE;
2815                     for (i = 0; validForUsage &&
2816                      i < requestedUsage->cUsageIdentifier; i++)
2817                     {
2818                         BOOL match = FALSE;
2819 
2820                         for (j = 0; !match && j < usage->cUsageIdentifier; j++)
2821                             match = !strcmp(usage->rgpszUsageIdentifier[j],
2822                              requestedUsage->rgpszUsageIdentifier[i]);
2823                         if (!match)
2824                             validForUsage = FALSE;
2825                     }
2826                 }
2827                 else
2828                 {
2829                     DWORD i, j;
2830 
2831                     /* For OR matches, any matching usage suffices */
2832                     validForUsage = FALSE;
2833                     for (i = 0; !validForUsage &&
2834                      i < requestedUsage->cUsageIdentifier; i++)
2835                     {
2836                         for (j = 0; !validForUsage &&
2837                          j < usage->cUsageIdentifier; j++)
2838                             validForUsage =
2839                              !strcmp(usage->rgpszUsageIdentifier[j],
2840                              requestedUsage->rgpszUsageIdentifier[i]);
2841                     }
2842                 }
2843                 LocalFree(usage);
2844             }
2845             else
2846                 validForUsage = FALSE;
2847         }
2848         else
2849         {
2850             /* If the extension isn't present, any interpretation is valid:
2851              * "Certificate using applications MAY require that the extended
2852              *  key usage extension be present and that a particular purpose
2853              *  be indicated in order for the certificate to be acceptable to
2854              *  that application."
2855              * Not all web sites include the extended key usage extension, so
2856              * accept chains without it.
2857              */
2858             TRACE_(chain)("requested usage from certificate with no usages\n");
2859             validForUsage = TRUE;
2860         }
2861         if (!validForUsage)
2862         {
2863             chain->TrustStatus.dwErrorStatus |=
2864              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
2865             chain->rgpChain[0]->rgpElement[0]->TrustStatus.dwErrorStatus |=
2866              CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
2867         }
2868     }
2869     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA) &&
2870      pChainPara->RequestedIssuancePolicy.Usage.cUsageIdentifier)
2871         FIXME("unimplemented for RequestedIssuancePolicy\n");
2872 }
2873 
2874 static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch)
2875 {
2876     if (usageMatch->Usage.cUsageIdentifier)
2877     {
2878         DWORD i;
2879 
2880         TRACE_(chain)("%s: %s\n", name,
2881          usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR");
2882         for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++)
2883             TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]);
2884     }
2885 }
2886 
2887 static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara)
2888 {
2889     TRACE_(chain)("%d\n", pChainPara->cbSize);
2890     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS))
2891         dump_usage_match("RequestedUsage", &pChainPara->RequestedUsage);
2892     if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA))
2893     {
2894         dump_usage_match("RequestedIssuancePolicy",
2895          &pChainPara->RequestedIssuancePolicy);
2896         TRACE_(chain)("%d\n", pChainPara->dwUrlRetrievalTimeout);
2897         TRACE_(chain)("%d\n", pChainPara->fCheckRevocationFreshnessTime);
2898         TRACE_(chain)("%d\n", pChainPara->dwRevocationFreshnessTime);
2899     }
2900 }
2901 
2902 BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
2903  PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
2904  PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
2905  PCCERT_CHAIN_CONTEXT* ppChainContext)
2906 {
2907     CertificateChainEngine *engine;
2908     BOOL ret;
2909     CertificateChain *chain = NULL;
2910 
2911     TRACE("(%p, %p, %s, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext,
2912      debugstr_filetime(pTime), hAdditionalStore, pChainPara, dwFlags,
2913      pvReserved, ppChainContext);
2914 
2915     engine = get_chain_engine(hChainEngine, TRUE);
2916     if (!engine)
2917         return FALSE;
2918 
2919     if (ppChainContext)
2920         *ppChainContext = NULL;
2921     if (!pChainPara)
2922     {
2923         SetLastError(E_INVALIDARG);
2924         return FALSE;
2925     }
2926     if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)
2927     {
2928         SetLastError(ERROR_INVALID_DATA);
2929         return FALSE;
2930     }
2931 
2932     if (TRACE_ON(chain))
2933         dump_chain_para(pChainPara);
2934     /* FIXME: what about HCCE_LOCAL_MACHINE? */
2935     ret = CRYPT_BuildCandidateChainFromCert(engine, pCertContext, pTime,
2936      hAdditionalStore, dwFlags, &chain);
2937     if (ret)
2938     {
2939         CertificateChain *alternate = NULL;
2940         PCERT_CHAIN_CONTEXT pChain;
2941 
2942         do {
2943             alternate = CRYPT_BuildAlternateContextFromChain(engine,
2944              pTime, hAdditionalStore, dwFlags, chain);
2945 
2946             /* Alternate contexts are added as "lower quality" contexts of
2947              * chain, to avoid loops in alternate chain creation.
2948              * The highest-quality chain is chosen at the end.
2949              */
2950             if (alternate)
2951                 ret = CRYPT_AddAlternateChainToChain(chain, alternate);
2952         } while (ret && alternate);
2953         chain = CRYPT_ChooseHighestQualityChain(chain);
2954         if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
2955             CRYPT_FreeLowerQualityChains(chain);
2956         pChain = (PCERT_CHAIN_CONTEXT)chain;
2957         CRYPT_VerifyChainRevocation(pChain, pTime, hAdditionalStore,
2958          pChainPara, dwFlags);
2959         CRYPT_CheckUsages(pChain, pChainPara);
2960         TRACE_(chain)("error status: %08x\n",
2961          pChain->TrustStatus.dwErrorStatus);
2962         if (ppChainContext)
2963             *ppChainContext = pChain;
2964         else
2965             CertFreeCertificateChain(pChain);
2966     }
2967     TRACE("returning %d\n", ret);
2968     return ret;
2969 }
2970 
2971 PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain(
2972  PCCERT_CHAIN_CONTEXT pChainContext)
2973 {
2974     CertificateChain *chain = (CertificateChain*)pChainContext;
2975 
2976     TRACE("(%p)\n", pChainContext);
2977 
2978     if (chain)
2979         InterlockedIncrement(&chain->ref);
2980     return pChainContext;
2981 }
2982 
2983 VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext)
2984 {
2985     CertificateChain *chain = (CertificateChain*)pChainContext;
2986 
2987     TRACE("(%p)\n", pChainContext);
2988 
2989     if (chain)
2990     {
2991         if (InterlockedDecrement(&chain->ref) == 0)
2992             CRYPT_FreeChainContext(chain);
2993     }
2994 }
2995 
2996 PCCERT_CHAIN_CONTEXT WINAPI CertFindChainInStore(HCERTSTORE store,
2997  DWORD certEncodingType, DWORD findFlags, DWORD findType,
2998  const void *findPara, PCCERT_CHAIN_CONTEXT prevChainContext)
2999 {
3000     FIXME("(%p, %08x, %08x, %d, %p, %p): stub\n", store, certEncodingType,
3001      findFlags, findType, findPara, prevChainContext);
3002     return NULL;
3003 }
3004 
3005 static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error,
3006  LONG *iChain, LONG *iElement)
3007 {
3008     DWORD i, j;
3009 
3010     for (i = 0; i < chain->cChain; i++)
3011         for (j = 0; j < chain->rgpChain[i]->cElement; j++)
3012             if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus &
3013              error)
3014             {
3015                 *iChain = i;
3016                 *iElement = j;
3017                 return;
3018             }
3019 }
3020 
3021 static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID,
3022  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3023  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
3024 {
3025     DWORD checks = 0;
3026 
3027     if (pPolicyPara)
3028         checks = pPolicyPara->dwFlags;
3029     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
3030     pPolicyStatus->dwError = NO_ERROR;
3031     if (pChainContext->TrustStatus.dwErrorStatus &
3032      CERT_TRUST_IS_NOT_SIGNATURE_VALID)
3033     {
3034         pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
3035         find_element_with_error(pChainContext,
3036          CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
3037          &pPolicyStatus->lElementIndex);
3038     }
3039     else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
3040     {
3041         pPolicyStatus->dwError = CERT_E_CHAINING;
3042         find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC,
3043          &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex);
3044         /* For a cyclic chain, which element is a cycle isn't meaningful */
3045         pPolicyStatus->lElementIndex = -1;
3046     }
3047     if (!pPolicyStatus->dwError &&
3048      pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT &&
3049      !(checks & CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG))
3050     {
3051         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
3052         find_element_with_error(pChainContext,
3053          CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
3054          &pPolicyStatus->lElementIndex);
3055     }
3056     if (!pPolicyStatus->dwError &&
3057      pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
3058     {
3059         pPolicyStatus->dwError = CERT_E_EXPIRED;
3060         find_element_with_error(pChainContext,
3061          CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex,
3062          &pPolicyStatus->lElementIndex);
3063     }
3064     if (!pPolicyStatus->dwError &&
3065      pChainContext->TrustStatus.dwErrorStatus &
3066      CERT_TRUST_IS_NOT_VALID_FOR_USAGE &&
3067      !(checks & CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG))
3068     {
3069         pPolicyStatus->dwError = CERT_E_WRONG_USAGE;
3070         find_element_with_error(pChainContext,
3071          CERT_TRUST_IS_NOT_VALID_FOR_USAGE, &pPolicyStatus->lChainIndex,
3072          &pPolicyStatus->lElementIndex);
3073     }
3074     if (!pPolicyStatus->dwError &&
3075      pChainContext->TrustStatus.dwErrorStatus &
3076      CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT &&
3077      !(checks & CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG))
3078     {
3079         pPolicyStatus->dwError = CERT_E_CRITICAL;
3080         find_element_with_error(pChainContext,
3081          CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, &pPolicyStatus->lChainIndex,
3082          &pPolicyStatus->lElementIndex);
3083     }
3084     return TRUE;
3085 }
3086 
3087 static BYTE msTestPubKey1[] = {
3088 0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9,
3089 0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7,
3090 0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f,
3091 0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10,
3092 0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
3093 static BYTE msTestPubKey2[] = {
3094 0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5,
3095 0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8,
3096 0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6,
3097 0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18,
3098 0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 };
3099 
3100 static void dump_authenticode_extra_chain_policy_para(
3101  AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA *extraPara)
3102 {
3103     if (extraPara)
3104     {
3105         TRACE_(chain)("cbSize = %d\n", extraPara->cbSize);
3106         TRACE_(chain)("dwRegPolicySettings = %08x\n",
3107          extraPara->dwRegPolicySettings);
3108         TRACE_(chain)("pSignerInfo = %p\n", extraPara->pSignerInfo);
3109     }
3110 }
3111 
3112 static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID,
3113  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3114  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
3115 {
3116     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
3117      pPolicyStatus);
3118     AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA *extraPara = NULL;
3119 
3120     if (pPolicyPara)
3121         extraPara = pPolicyPara->pvExtraPolicyPara;
3122     if (TRACE_ON(chain))
3123         dump_authenticode_extra_chain_policy_para(extraPara);
3124     if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT)
3125     {
3126         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
3127         BOOL isMSTestRoot = FALSE;
3128         PCCERT_CONTEXT failingCert =
3129          pChainContext->rgpChain[pPolicyStatus->lChainIndex]->
3130          rgpElement[pPolicyStatus->lElementIndex]->pCertContext;
3131         DWORD i;
3132         CRYPT_DATA_BLOB keyBlobs[] = {
3133          { sizeof(msTestPubKey1), msTestPubKey1 },
3134          { sizeof(msTestPubKey2), msTestPubKey2 },
3135         };
3136 
3137         /* Check whether the root is an MS test root */
3138         for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
3139          i++)
3140         {
3141             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
3142             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
3143             if (CertComparePublicKeyInfo(
3144              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
3145              &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
3146                 isMSTestRoot = TRUE;
3147         }
3148         if (isMSTestRoot)
3149             pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT;
3150     }
3151     return ret;
3152 }
3153 
3154 static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID,
3155  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3156  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
3157 {
3158     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
3159     if (pChainContext->TrustStatus.dwErrorStatus &
3160      CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
3161     {
3162         pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS;
3163         find_element_with_error(pChainContext,
3164          CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex,
3165          &pPolicyStatus->lElementIndex);
3166     }
3167     else
3168         pPolicyStatus->dwError = NO_ERROR;
3169     return TRUE;
3170 }
3171 
3172 static BOOL match_dns_to_subject_alt_name(const CERT_EXTENSION *ext,
3173  LPCWSTR server_name)
3174 {
3175     BOOL matches = FALSE;
3176     CERT_ALT_NAME_INFO *subjectName;
3177     DWORD size;
3178 
3179     TRACE_(chain)("%s\n", debugstr_w(server_name));
3180     /* This could be spoofed by the embedded NULL vulnerability, since the
3181      * returned CERT_ALT_NAME_INFO doesn't have a way to indicate the
3182      * encoded length of a name.  Fortunately CryptDecodeObjectEx fails if
3183      * the encoded form of the name contains a NULL.
3184      */
3185     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
3186      ext->Value.pbData, ext->Value.cbData,
3187      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
3188      &subjectName, &size))
3189     {
3190         DWORD i;
3191 
3192         /* RFC 5280 states that multiple instances of each name type may exist,
3193          * in section 4.2.1.6:
3194          * "Multiple name forms, and multiple instances of each name form,
3195          *  MAY be included."
3196          * It doesn't specify the behavior in such cases, but both RFC 2818
3197          * and RFC 2595 explicitly accept a certificate if any name matches.
3198          */
3199         for (i = 0; !matches && i < subjectName->cAltEntry; i++)
3200         {
3201             if (subjectName->rgAltEntry[i].dwAltNameChoice ==
3202              CERT_ALT_NAME_DNS_NAME)
3203             {
3204                 TRACE_(chain)("dNSName: %s\n", debugstr_w(
3205                  subjectName->rgAltEntry[i].u.pwszDNSName));
3206                 if (subjectName->rgAltEntry[i].u.pwszDNSName[0] == '*')
3207                 {
3208                     LPCWSTR server_name_dot;
3209 
3210                     /* Matching a wildcard: a wildcard matches a single name
3211                      * component, which is terminated by a dot.  RFC 1034
3212                      * doesn't define whether multiple wildcards are allowed,
3213                      * but I will assume that they are not until proven
3214                      * otherwise.  RFC 1034 also states that 'the "*" label
3215                      * always matches at least one whole label and sometimes
3216                      * more, but always whole labels.'  Native crypt32 does not
3217                      * match more than one label with a wildcard, so I do the
3218                      * same here.  Thus, a wildcard only accepts the first
3219                      * label, then requires an exact match of the remaining
3220                      * string.
3221                      */
3222                     server_name_dot = strchrW(server_name, '.');
3223                     if (server_name_dot)
3224                     {
3225                         if (!strcmpiW(server_name_dot,
3226                          subjectName->rgAltEntry[i].u.pwszDNSName + 1))
3227                             matches = TRUE;
3228                     }
3229                 }
3230                 else if (!strcmpiW(server_name,
3231                  subjectName->rgAltEntry[i].u.pwszDNSName))
3232                     matches = TRUE;
3233             }
3234         }
3235         LocalFree(subjectName);
3236     }
3237     return matches;
3238 }
3239 
3240 static BOOL find_matching_domain_component(const CERT_NAME_INFO *name,
3241  LPCWSTR component)
3242 {
3243     BOOL matches = FALSE;
3244     DWORD i, j;
3245 
3246     for (i = 0; !matches && i < name->cRDN; i++)
3247         for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
3248             if (!strcmp(szOID_DOMAIN_COMPONENT,
3249              name->rgRDN[i].rgRDNAttr[j].pszObjId))
3250             {
3251                 const CERT_RDN_ATTR *attr;
3252 
3253                 attr = &name->rgRDN[i].rgRDNAttr[j];
3254                 /* Compare with memicmpW rather than strcmpiW in order to avoid
3255                  * a match with a string with an embedded NULL.  The component
3256                  * must match one domain component attribute's entire string
3257                  * value with a case-insensitive match.
3258                  */
3259                 matches = !memicmpW(component, (LPCWSTR)attr->Value.pbData,
3260                  attr->Value.cbData / sizeof(WCHAR));
3261             }
3262     return matches;
3263 }
3264 
3265 static BOOL match_domain_component(LPCWSTR allowed_component, DWORD allowed_len,
3266  LPCWSTR server_component, DWORD server_len, BOOL allow_wildcards,
3267  BOOL *see_wildcard)
3268 {
3269     LPCWSTR allowed_ptr, server_ptr;
3270     BOOL matches = TRUE;
3271 
3272     *see_wildcard = FALSE;
3273 
3274     if (server_len < allowed_len)
3275     {
3276         WARN_(chain)("domain component %s too short for %s\n",
3277          debugstr_wn(server_component, server_len),
3278          debugstr_wn(allowed_component, allowed_len));
3279         /* A domain component can't contain a wildcard character, so a domain
3280          * component shorter than the allowed string can't produce a match.
3281          */
3282         return FALSE;
3283     }
3284     for (allowed_ptr = allowed_component, server_ptr = server_component;
3285          matches && allowed_ptr - allowed_component < allowed_len;
3286          allowed_ptr++, server_ptr++)
3287     {
3288         if (*allowed_ptr == '*')
3289         {
3290             if (allowed_ptr - allowed_component < allowed_len - 1)
3291             {
3292                 WARN_(chain)("non-wildcard characters after wildcard not supported\n");
3293                 matches = FALSE;
3294             }
3295             else if (!allow_wildcards)
3296             {
3297                 WARN_(chain)("wildcard after non-wildcard component\n");
3298                 matches = FALSE;
3299             }
3300             else
3301             {
3302                 /* the preceding characters must have matched, so the rest of
3303                  * the component also matches.
3304                  */
3305                 *see_wildcard = TRUE;
3306                 break;
3307             }
3308         }
3309         if (matches)
3310             matches = tolowerW(*allowed_ptr) == tolowerW(*server_ptr);
3311     }
3312     if (matches && server_ptr - server_component < server_len)
3313     {
3314         /* If there are unmatched characters in the server domain component,
3315          * the server domain only matches if the allowed string ended in a '*'.
3316          */
3317         matches = *allowed_ptr == '*';
3318     }
3319     return matches;
3320 }
3321 
3322 static BOOL match_common_name(LPCWSTR server_name, const CERT_RDN_ATTR *nameAttr)
3323 {
3324     LPCWSTR allowed = (LPCWSTR)nameAttr->Value.pbData;
3325     LPCWSTR allowed_component = allowed;
3326     DWORD allowed_len = nameAttr->Value.cbData / sizeof(WCHAR);
3327     LPCWSTR server_component = server_name;
3328     DWORD server_len = strlenW(server_name);
3329     BOOL matches = TRUE, allow_wildcards = TRUE;
3330 
3331     TRACE_(chain)("CN = %s\n", debugstr_wn(allowed_component, allowed_len));
3332 
3333     /* Remove trailing NULLs from the allowed name; while they shouldn't appear
3334      * in a certificate in the first place, they sometimes do, and they should
3335      * be ignored.
3336      */
3337     while (allowed_len && allowed_component[allowed_len - 1] == 0)
3338       allowed_len--;
3339 
3340     /* From RFC 2818 (HTTP over TLS), section 3.1:
3341      * "Names may contain the wildcard character * which is considered to match
3342      *  any single domain name component or component fragment. E.g.,
3343      *  *.a.com matches foo.a.com but not bar.foo.a.com. f*.com matches foo.com
3344      *  but not bar.com."
3345      *
3346      * And from RFC 2595 (Using TLS with IMAP, POP3 and ACAP), section 2.4:
3347      * "A "*" wildcard character MAY be used as the left-most name component in
3348      *  the certificate.  For example, *.example.com would match a.example.com,
3349      *  foo.example.com, etc. but would not match example.com."
3350      *
3351      * There are other protocols which use TLS, and none of them is
3352      * authoritative.  This accepts certificates in common usage, e.g.
3353      * *.domain.com matches www.domain.com but not domain.com, and
3354      * www*.domain.com matches www1.domain.com but not mail.domain.com.
3355      */
3356     do {
3357         LPCWSTR allowed_dot, server_dot;
3358 
3359         allowed_dot = memchrW(allowed_component, '.',
3360          allowed_len - (allowed_component - allowed));
3361         server_dot = memchrW(server_component, '.',
3362          server_len - (server_component - server_name));
3363         /* The number of components must match */
3364         if ((!allowed_dot && server_dot) || (allowed_dot && !server_dot))
3365         {
3366             if (!allowed_dot)
3367                 WARN_(chain)("%s: too many components for CN=%s\n",
3368                  debugstr_w(server_name), debugstr_wn(allowed, allowed_len));
3369             else
3370                 WARN_(chain)("%s: not enough components for CN=%s\n",
3371                  debugstr_w(server_name), debugstr_wn(allowed, allowed_len));
3372             matches = FALSE;
3373         }
3374         else
3375         {
3376             LPCWSTR allowed_end, server_end;
3377             BOOL has_wildcard;
3378 
3379             allowed_end = allowed_dot ? allowed_dot : allowed + allowed_len;
3380             server_end = server_dot ? server_dot : server_name + server_len;
3381             matches = match_domain_component(allowed_component,
3382              allowed_end - allowed_component, server_component,
3383              server_end - server_component, allow_wildcards, &has_wildcard);
3384             /* Once a non-wildcard component is seen, no wildcard components
3385              * may follow
3386              */
3387             if (!has_wildcard)
3388                 allow_wildcards = FALSE;
3389             if (matches)
3390             {
3391                 allowed_component = allowed_dot ? allowed_dot + 1 : allowed_end;
3392                 server_component = server_dot ? server_dot + 1 : server_end;
3393             }
3394         }
3395     } while (matches && allowed_component &&
3396      allowed_component - allowed < allowed_len &&
3397      server_component && server_component - server_name < server_len);
3398     TRACE_(chain)("returning %d\n", matches);
3399     return matches;
3400 }
3401 
3402 static BOOL match_dns_to_subject_dn(PCCERT_CONTEXT cert, LPCWSTR server_name)
3403 {
3404     BOOL matches = FALSE;
3405     CERT_NAME_INFO *name;
3406     DWORD size;
3407 
3408     TRACE_(chain)("%s\n", debugstr_w(server_name));
3409     if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME,
3410      cert->pCertInfo->Subject.pbData, cert->pCertInfo->Subject.cbData,
3411      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
3412      &name, &size))
3413     {
3414         /* If the subject distinguished name contains any name components,
3415          * make sure all of them are present.
3416          */
3417         if (CertFindRDNAttr(szOID_DOMAIN_COMPONENT, name))
3418         {
3419             LPCWSTR ptr = server_name;
3420 
3421             do {
3422                 LPCWSTR dot = strchrW(ptr, '.'), end;
3423                 /* 254 is the maximum DNS label length, see RFC 1035 */
3424                 WCHAR component[255];
3425                 DWORD len;
3426 
3427                 end = dot ? dot : ptr + strlenW(ptr);
3428                 len = end - ptr;
3429                 if (len >= sizeof(component) / sizeof(component[0]))
3430                 {
3431                     WARN_(chain)("domain component %s too long\n",
3432                      debugstr_wn(ptr, len));
3433                     matches = FALSE;
3434                 }
3435                 else
3436                 {
3437                     memcpy(component, ptr, len * sizeof(WCHAR));
3438                     component[len] = 0;
3439                     matches = find_matching_domain_component(name, component);
3440                 }
3441                 ptr = dot ? dot + 1 : end;
3442             } while (matches && ptr && *ptr);
3443         }
3444         else
3445         {
3446             DWORD i, j;
3447 
3448             /* If the certificate isn't using a DN attribute in the name, make
3449              * make sure at least one common name matches.  From RFC 2818,
3450              * section 3.1:
3451              * "If more than one identity of a given type is present in the
3452              * certificate (e.g., more than one dNSName name, a match in any
3453              * one of the set is considered acceptable.)"
3454              */
3455             for (i = 0; !matches && i < name->cRDN; i++)
3456                 for (j = 0; !matches && j < name->rgRDN[i].cRDNAttr; j++)
3457                 {
3458                     PCERT_RDN_ATTR attr = &name->rgRDN[i].rgRDNAttr[j];
3459 
3460                     if (attr->pszObjId && !strcmp(szOID_COMMON_NAME,
3461                      attr->pszObjId))
3462                         matches = match_common_name(server_name, attr);
3463                 }
3464         }
3465         LocalFree(name);
3466     }
3467     return matches;
3468 }
3469 
3470 static void dump_ssl_extra_chain_policy_para(HTTPSPolicyCallbackData *sslPara)
3471 {
3472     if (sslPara)
3473     {
3474         TRACE_(chain)("cbSize = %d\n", sslPara->u.cbSize);
3475         TRACE_(chain)("dwAuthType = %d\n", sslPara->dwAuthType);
3476         TRACE_(chain)("fdwChecks = %08x\n", sslPara->fdwChecks);
3477         TRACE_(chain)("pwszServerName = %s\n",
3478          debugstr_w(sslPara->pwszServerName));
3479     }
3480 }
3481 
3482 static BOOL WINAPI verify_ssl_policy(LPCSTR szPolicyOID,
3483  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3484  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
3485 {
3486     HTTPSPolicyCallbackData *sslPara = NULL;
3487     DWORD checks = 0;
3488 
3489     if (pPolicyPara)
3490         sslPara = pPolicyPara->pvExtraPolicyPara;
3491     if (TRACE_ON(chain))
3492         dump_ssl_extra_chain_policy_para(sslPara);
3493     if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData))
3494         checks = sslPara->fdwChecks;
3495     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
3496     if (pChainContext->TrustStatus.dwErrorStatus &
3497      CERT_TRUST_IS_NOT_SIGNATURE_VALID)
3498     {
3499         pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
3500         find_element_with_error(pChainContext,
3501          CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
3502          &pPolicyStatus->lElementIndex);
3503     }
3504     else if (pChainContext->TrustStatus.dwErrorStatus &
3505      CERT_TRUST_IS_UNTRUSTED_ROOT &&
3506      !(checks & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
3507     {
3508         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
3509         find_element_with_error(pChainContext,
3510          CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
3511          &pPolicyStatus->lElementIndex);
3512     }
3513     else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
3514     {
3515         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
3516         find_element_with_error(pChainContext,
3517          CERT_TRUST_IS_CYCLIC, &pPolicyStatus->lChainIndex,
3518          &pPolicyStatus->lElementIndex);
3519         /* For a cyclic chain, which element is a cycle isn't meaningful */
3520         pPolicyStatus->lElementIndex = -1;
3521     }
3522     else if (pChainContext->TrustStatus.dwErrorStatus &
3523      CERT_TRUST_IS_NOT_TIME_VALID &&
3524      !(checks & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
3525     {
3526         pPolicyStatus->dwError = CERT_E_EXPIRED;
3527         find_element_with_error(pChainContext,
3528          CERT_TRUST_IS_NOT_TIME_VALID, &pPolicyStatus->lChainIndex,
3529          &pPolicyStatus->lElementIndex);
3530     }
3531     else if (pChainContext->TrustStatus.dwErrorStatus &
3532      CERT_TRUST_IS_NOT_VALID_FOR_USAGE &&
3533      !(checks & SECURITY_FLAG_IGNORE_WRONG_USAGE))
3534     {
3535         pPolicyStatus->dwError = CERT_E_WRONG_USAGE;
3536         find_element_with_error(pChainContext,
3537          CERT_TRUST_IS_NOT_VALID_FOR_USAGE, &pPolicyStatus->lChainIndex,
3538          &pPolicyStatus->lElementIndex);
3539     }
3540     else if (pChainContext->TrustStatus.dwErrorStatus &
3541      CERT_TRUST_IS_REVOKED && !(checks & SECURITY_FLAG_IGNORE_REVOCATION))
3542     {
3543         pPolicyStatus->dwError = CERT_E_REVOKED;
3544         find_element_with_error(pChainContext,
3545          CERT_TRUST_IS_REVOKED, &pPolicyStatus->lChainIndex,
3546          &pPolicyStatus->lElementIndex);
3547     }
3548     else if (pChainContext->TrustStatus.dwErrorStatus &
3549      CERT_TRUST_IS_OFFLINE_REVOCATION &&
3550      !(checks & SECURITY_FLAG_IGNORE_REVOCATION))
3551     {
3552         pPolicyStatus->dwError = CERT_E_REVOCATION_FAILURE;
3553         find_element_with_error(pChainContext,
3554          CERT_TRUST_IS_OFFLINE_REVOCATION, &pPolicyStatus->lChainIndex,
3555          &pPolicyStatus->lElementIndex);
3556     }
3557     else if (pChainContext->TrustStatus.dwErrorStatus &
3558      CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT)
3559     {
3560         pPolicyStatus->dwError = CERT_E_CRITICAL;
3561         find_element_with_error(pChainContext,
3562          CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, &pPolicyStatus->lChainIndex,
3563          &pPolicyStatus->lElementIndex);
3564     }
3565     else
3566         pPolicyStatus->dwError = NO_ERROR;
3567     /* We only need bother checking whether the name in the end certificate
3568      * matches if the chain is otherwise okay.
3569      */
3570     if (!pPolicyStatus->dwError && pPolicyPara &&
3571      pPolicyPara->cbSize >= sizeof(CERT_CHAIN_POLICY_PARA))
3572     {
3573         if (sslPara && sslPara->u.cbSize >= sizeof(HTTPSPolicyCallbackData))
3574         {
3575             if (sslPara->dwAuthType == AUTHTYPE_SERVER &&
3576              sslPara->pwszServerName &&
3577              !(checks & SECURITY_FLAG_IGNORE_CERT_CN_INVALID))
3578             {
3579                 PCCERT_CONTEXT cert;
3580                 PCERT_EXTENSION altNameExt;
3581                 BOOL matches;
3582 
3583                 cert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
3584                 altNameExt = get_subject_alt_name_ext(cert->pCertInfo);
3585                 /* If the alternate name extension exists, the name it contains
3586                  * is bound to the certificate, so make sure the name matches
3587                  * it.  Otherwise, look for the server name in the subject
3588                  * distinguished name.  RFC5280, section 4.2.1.6:
3589                  * "Whenever such identities are to be bound into a
3590                  *  certificate, the subject alternative name (or issuer
3591                  *  alternative name) extension MUST be used; however, a DNS
3592                  *  name MAY also be represented in the subject field using the
3593                  *  domainComponent attribute."
3594                  */
3595                 if (altNameExt)
3596                     matches = match_dns_to_subject_alt_name(altNameExt,
3597                      sslPara->pwszServerName);
3598                 else
3599                     matches = match_dns_to_subject_dn(cert,
3600                      sslPara->pwszServerName);
3601                 if (!matches)
3602                 {
3603                     pPolicyStatus->dwError = CERT_E_CN_NO_MATCH;
3604                     pPolicyStatus->lChainIndex = 0;
3605                     pPolicyStatus->lElementIndex = 0;
3606                 }
3607             }
3608         }
3609     }
3610     return TRUE;
3611 }
3612 
3613 static BYTE msPubKey1[] = {
3614 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
3615 0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
3616 0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29,
3617 0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16,
3618 0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60,
3619 0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5,
3620 0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d,
3621 0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61,
3622 0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e,
3623 0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94,
3624 0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb,
3625 0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a,
3626 0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d,
3627 0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb,
3628 0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08,
3629 0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43,
3630 0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf,
3631 0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 };
3632 static BYTE msPubKey2[] = {
3633 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6,
3634 0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25,
3635 0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2,
3636 0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54,
3637 0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62,
3638 0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a,
3639 0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7,
3640 0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84,
3641 0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9,
3642 0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91,
3643 0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52,
3644 0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80,
3645 0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18,
3646 0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07,
3647 0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef,
3648 0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0,
3649 0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30,
3650 0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 };
3651 static BYTE msPubKey3[] = {
3652 0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4,
3653 0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7,
3654 0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94,
3655 0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04,
3656 0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d,
3657 0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09,
3658 0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae,
3659 0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7,
3660 0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f,
3661 0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94,
3662 0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d,
3663 0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05,
3664 0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e,
3665 0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d,
3666 0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b,
3667 0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67,
3668 0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08,
3669 0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5,
3670 0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64,
3671 0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38,
3672 0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0,
3673 0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9,
3674 0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28,
3675 0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc,
3676 0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45,
3677 0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde,
3678 0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04,
3679 0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89,
3680 0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11,
3681 0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32,
3682 0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40,
3683 0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41,
3684 0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1,
3685 0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5,
3686 0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00,
3687 0x01 };
3688 
3689 static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
3690  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3691  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
3692 {
3693     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
3694      pPolicyStatus);
3695 
3696     if (ret && !pPolicyStatus->dwError)
3697     {
3698         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
3699         BOOL isMSRoot = FALSE;
3700         DWORD i;
3701         CRYPT_DATA_BLOB keyBlobs[] = {
3702          { sizeof(msPubKey1), msPubKey1 },
3703          { sizeof(msPubKey2), msPubKey2 },
3704          { sizeof(msPubKey3), msPubKey3 },
3705         };
3706         PCERT_SIMPLE_CHAIN rootChain =
3707          pChainContext->rgpChain[pChainContext->cChain -1 ];
3708         PCCERT_CONTEXT root =
3709          rootChain->rgpElement[rootChain->cElement - 1]->pCertContext;
3710 
3711         for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
3712          i++)
3713         {
3714             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
3715             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
3716             if (CertComparePublicKeyInfo(
3717              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
3718              &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
3719                 isMSRoot = TRUE;
3720         }
3721         if (isMSRoot)
3722             pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0;
3723     }
3724     return ret;
3725 }
3726 
3727 typedef BOOL (WINAPI *CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID,
3728  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3729  PCERT_CHAIN_POLICY_STATUS pPolicyStatus);
3730 
3731 static void dump_policy_para(PCERT_CHAIN_POLICY_PARA para)
3732 {
3733     if (para)
3734     {
3735         TRACE_(chain)("cbSize = %d\n", para->cbSize);
3736         TRACE_(chain)("dwFlags = %08x\n", para->dwFlags);
3737         TRACE_(chain)("pvExtraPolicyPara = %p\n", para->pvExtraPolicyPara);
3738     }
3739 }
3740 
3741 BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID,
3742  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
3743  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
3744 {
3745     static HCRYPTOIDFUNCSET set = NULL;
3746     BOOL ret = FALSE;
3747     CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL;
3748     HCRYPTOIDFUNCADDR hFunc = NULL;
3749 
3750     TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext,
3751      pPolicyPara, pPolicyStatus);
3752     if (TRACE_ON(chain))
3753         dump_policy_para(pPolicyPara);
3754 
3755     if (IS_INTOID(szPolicyOID))
3756     {
3757         switch (LOWORD(szPolicyOID))
3758         {
3759         case LOWORD(CERT_CHAIN_POLICY_BASE):
3760             verifyPolicy = verify_base_policy;
3761             break;
3762         case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE):
3763             verifyPolicy = verify_authenticode_policy;
3764             break;
3765         case LOWORD(CERT_CHAIN_POLICY_SSL):
3766             verifyPolicy = verify_ssl_policy;
3767             break;
3768         case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS):
3769             verifyPolicy = verify_basic_constraints_policy;
3770             break;
3771         case LOWORD(CERT_CHAIN_POLICY_MICROSOFT_ROOT):
3772             verifyPolicy = verify_ms_root_policy;
3773             break;
3774         default:
3775             FIXME("unimplemented for %d\n", LOWORD(szPolicyOID));
3776         }
3777     }
3778     if (!verifyPolicy)
3779     {
3780         if (!set)
3781             set = CryptInitOIDFunctionSet(
3782              CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0);
3783         CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0,
3784          (void **)&verifyPolicy, &hFunc);
3785     }
3786     if (verifyPolicy)
3787         ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara,
3788          pPolicyStatus);
3789     if (hFunc)
3790         CryptFreeOIDFunctionAddress(hFunc, 0);
3791     TRACE("returning %d (%08x)\n", ret, pPolicyStatus->dwError);
3792     return ret;
3793 }
3794