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