comctl32: Monthcal should send notifications when today link gets clicked.
[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 #include "wincrypt.h"
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26 #include "crypt32_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
29
30 #define DEFAULT_CYCLE_MODULUS 7
31
32 static HCERTCHAINENGINE CRYPT_defaultChainEngine;
33
34 /* This represents a subset of a certificate chain engine:  it doesn't include
35  * the "hOther" store described by MSDN, because I'm not sure how that's used.
36  * It also doesn't include the "hTrust" store, because I don't yet implement
37  * CTLs or complex certificate chains.
38  */
39 typedef struct _CertificateChainEngine
40 {
41     LONG       ref;
42     HCERTSTORE hRoot;
43     HCERTSTORE hWorld;
44     DWORD      dwFlags;
45     DWORD      dwUrlRetrievalTimeout;
46     DWORD      MaximumCachedCertificates;
47     DWORD      CycleDetectionModulus;
48 } CertificateChainEngine, *PCertificateChainEngine;
49
50 static inline void CRYPT_AddStoresToCollection(HCERTSTORE collection,
51  DWORD cStores, HCERTSTORE *stores)
52 {
53     DWORD i;
54
55     for (i = 0; i < cStores; i++)
56         CertAddStoreToCollection(collection, stores[i], 0, 0);
57 }
58
59 static inline void CRYPT_CloseStores(DWORD cStores, HCERTSTORE *stores)
60 {
61     DWORD i;
62
63     for (i = 0; i < cStores; i++)
64         CertCloseStore(stores[i], 0);
65 }
66
67 static const WCHAR rootW[] = { 'R','o','o','t',0 };
68
69 static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store)
70 {
71     BOOL ret = TRUE;
72
73     if (store)
74     {
75         HCERTSTORE rootStore = CertOpenSystemStoreW(0, rootW);
76         PCCERT_CONTEXT cert = NULL, check;
77         BYTE hash[20];
78         DWORD size;
79
80         do {
81             cert = CertEnumCertificatesInStore(store, cert);
82             if (cert)
83             {
84                 size = sizeof(hash);
85
86                 ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
87                  hash, &size);
88                 if (ret)
89                 {
90                     CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
91
92                     check = CertFindCertificateInStore(rootStore,
93                      cert->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
94                      NULL);
95                     if (!check)
96                         ret = FALSE;
97                     else
98                         CertFreeCertificateContext(check);
99                 }
100             }
101         } while (ret && cert);
102         if (cert)
103             CertFreeCertificateContext(cert);
104         CertCloseStore(rootStore, 0);
105     }
106     return ret;
107 }
108
109 HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root,
110  PCERT_CHAIN_ENGINE_CONFIG pConfig)
111 {
112     static const WCHAR caW[] = { 'C','A',0 };
113     static const WCHAR myW[] = { 'M','y',0 };
114     static const WCHAR trustW[] = { 'T','r','u','s','t',0 };
115     PCertificateChainEngine engine =
116      CryptMemAlloc(sizeof(CertificateChainEngine));
117
118     if (engine)
119     {
120         HCERTSTORE worldStores[4];
121
122         engine->ref = 1;
123         engine->hRoot = root;
124         engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
125          CERT_STORE_CREATE_NEW_FLAG, NULL);
126         worldStores[0] = CertDuplicateStore(engine->hRoot);
127         worldStores[1] = CertOpenSystemStoreW(0, caW);
128         worldStores[2] = CertOpenSystemStoreW(0, myW);
129         worldStores[3] = CertOpenSystemStoreW(0, trustW);
130         CRYPT_AddStoresToCollection(engine->hWorld,
131          sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
132         CRYPT_AddStoresToCollection(engine->hWorld,
133          pConfig->cAdditionalStore, pConfig->rghAdditionalStore);
134         CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]),
135          worldStores);
136         engine->dwFlags = pConfig->dwFlags;
137         engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout;
138         engine->MaximumCachedCertificates =
139          pConfig->MaximumCachedCertificates;
140         if (pConfig->CycleDetectionModulus)
141             engine->CycleDetectionModulus = pConfig->CycleDetectionModulus;
142         else
143             engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS;
144     }
145     return (HCERTCHAINENGINE)engine;
146 }
147
148 BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
149  HCERTCHAINENGINE *phChainEngine)
150 {
151     BOOL ret;
152
153     TRACE("(%p, %p)\n", pConfig, phChainEngine);
154
155     if (pConfig->cbSize != sizeof(*pConfig))
156     {
157         SetLastError(E_INVALIDARG);
158         return FALSE;
159     }
160     *phChainEngine = NULL;
161     ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot);
162     if (ret)
163     {
164         HCERTSTORE root;
165         HCERTCHAINENGINE engine;
166
167         if (pConfig->hRestrictedRoot)
168             root = CertDuplicateStore(pConfig->hRestrictedRoot);
169         else
170             root = CertOpenSystemStoreW(0, rootW);
171         engine = CRYPT_CreateChainEngine(root, pConfig);
172         if (engine)
173         {
174             *phChainEngine = engine;
175             ret = TRUE;
176         }
177         else
178             ret = FALSE;
179     }
180     return ret;
181 }
182
183 VOID WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
184 {
185     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
186
187     TRACE("(%p)\n", hChainEngine);
188
189     if (engine && InterlockedDecrement(&engine->ref) == 0)
190     {
191         CertCloseStore(engine->hWorld, 0);
192         CertCloseStore(engine->hRoot, 0);
193         CryptMemFree(engine);
194     }
195 }
196
197 static HCERTCHAINENGINE CRYPT_GetDefaultChainEngine(void)
198 {
199     if (!CRYPT_defaultChainEngine)
200     {
201         CERT_CHAIN_ENGINE_CONFIG config = { 0 };
202         HCERTCHAINENGINE engine;
203
204         config.cbSize = sizeof(config);
205         CertCreateCertificateChainEngine(&config, &engine);
206         InterlockedCompareExchangePointer(&CRYPT_defaultChainEngine, engine,
207          NULL);
208         if (CRYPT_defaultChainEngine != engine)
209             CertFreeCertificateChainEngine(engine);
210     }
211     return CRYPT_defaultChainEngine;
212 }
213
214 void default_chain_engine_free(void)
215 {
216     CertFreeCertificateChainEngine(CRYPT_defaultChainEngine);
217 }
218
219 typedef struct _CertificateChain
220 {
221     CERT_CHAIN_CONTEXT context;
222     HCERTSTORE world;
223     LONG ref;
224 } CertificateChain, *PCertificateChain;
225
226 static inline BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
227 {
228     return CertCompareCertificateName(cert->dwCertEncodingType,
229      &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
230 }
231
232 static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
233 {
234     CertFreeCertificateContext(element->pCertContext);
235     CryptMemFree(element);
236 }
237
238 static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain)
239 {
240     DWORD i, j, cyclicCertIndex = 0;
241
242     /* O(n^2) - I don't think there's a faster way */
243     for (i = 0; !cyclicCertIndex && i < chain->cElement; i++)
244         for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++)
245             if (CertCompareCertificate(X509_ASN_ENCODING,
246              chain->rgpElement[i]->pCertContext->pCertInfo,
247              chain->rgpElement[j]->pCertContext->pCertInfo))
248                 cyclicCertIndex = j;
249     if (cyclicCertIndex)
250     {
251         chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus
252          |= CERT_TRUST_IS_CYCLIC;
253         /* Release remaining certs */
254         for (i = cyclicCertIndex + 1; i < chain->cElement; i++)
255             CRYPT_FreeChainElement(chain->rgpElement[i]);
256         /* Truncate chain */
257         chain->cElement = cyclicCertIndex + 1;
258     }
259 }
260
261 /* Checks whether the chain is cyclic by examining the last element's status */
262 static inline BOOL CRYPT_IsSimpleChainCyclic(PCERT_SIMPLE_CHAIN chain)
263 {
264     if (chain->cElement)
265         return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus
266          & CERT_TRUST_IS_CYCLIC;
267     else
268         return FALSE;
269 }
270
271 static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus,
272  CERT_TRUST_STATUS *elementStatus)
273 {
274     /* Any error that applies to an element also applies to a chain.. */
275     chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus;
276     /* but the bottom nibble of an element's info status doesn't apply to the
277      * chain.
278      */
279     chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0);
280 }
281
282 static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine,
283  PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus)
284 {
285     BOOL ret = FALSE;
286     PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
287
288     if (element)
289     {
290         if (!chain->cElement)
291             chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT));
292         else
293             chain->rgpElement = CryptMemRealloc(chain->rgpElement,
294              (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
295         if (chain->rgpElement)
296         {
297             chain->rgpElement[chain->cElement++] = element;
298             memset(element, 0, sizeof(CERT_CHAIN_ELEMENT));
299             element->cbSize = sizeof(CERT_CHAIN_ELEMENT);
300             element->pCertContext = CertDuplicateCertificateContext(cert);
301             if (chain->cElement > 1)
302                 chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus
303                  = subjectInfoStatus;
304             /* FIXME: initialize the rest of element */
305             if (chain->cElement % engine->CycleDetectionModulus)
306                 CRYPT_CheckSimpleChainForCycles(chain);
307             CRYPT_CombineTrustStatus(&chain->TrustStatus,
308              &element->TrustStatus);
309             ret = TRUE;
310         }
311         else
312             CryptMemFree(element);
313     }
314     return ret;
315 }
316
317 static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
318 {
319     DWORD i;
320
321     for (i = 0; i < chain->cElement; i++)
322         CRYPT_FreeChainElement(chain->rgpElement[i]);
323     CryptMemFree(chain->rgpElement);
324     CryptMemFree(chain);
325 }
326
327 static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot,
328  PCERT_CHAIN_ELEMENT rootElement)
329 {
330     BYTE hash[20];
331     DWORD size = sizeof(hash);
332     CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
333     PCCERT_CONTEXT trustedRoot;
334
335     CertGetCertificateContextProperty(rootElement->pCertContext,
336      CERT_HASH_PROP_ID, hash, &size);
337     trustedRoot = CertFindCertificateInStore(hRoot,
338      rootElement->pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
339      &blob, NULL);
340     if (!trustedRoot)
341         rootElement->TrustStatus.dwErrorStatus |=
342          CERT_TRUST_IS_UNTRUSTED_ROOT;
343     else
344         CertFreeCertificateContext(trustedRoot);
345 }
346
347 static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot,
348  PCERT_CHAIN_ELEMENT rootElement)
349 {
350     PCCERT_CONTEXT root = rootElement->pCertContext;
351
352     if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType,
353      CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
354      CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
355     {
356         TRACE("Last certificate's signature is invalid\n");
357         rootElement->TrustStatus.dwErrorStatus |=
358          CERT_TRUST_IS_NOT_SIGNATURE_VALID;
359     }
360     CRYPT_CheckTrustedStatus(hRoot, rootElement);
361 }
362
363 /* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
364  * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a
365  * CERT_BASIC_CONSTRAINTS2_INFO.  If it neither extension is present, sets
366  * constraints->fCA to defaultIfNotSpecified.
367  * Returns FALSE if the extension is present but couldn't be decoded.
368  */
369 static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
370  CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified)
371 {
372     BOOL ret = TRUE;
373     PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
374      cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
375
376     constraints->fPathLenConstraint = FALSE;
377     if (ext)
378     {
379         CERT_BASIC_CONSTRAINTS_INFO *info;
380         DWORD size = 0;
381
382         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
383          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
384          NULL, (LPBYTE)&info, &size);
385         if (ret)
386         {
387             if (info->SubjectType.cbData == 1)
388                 constraints->fCA =
389                  info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
390             LocalFree(info);
391         }
392     }
393     else
394     {
395         ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
396          cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
397         if (ext)
398         {
399             DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
400
401             ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
402              szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
403              0, NULL, constraints, &size);
404         }
405         else
406             constraints->fCA = defaultIfNotSpecified;
407     }
408     return ret;
409 }
410
411 /* Checks element's basic constraints to see if it can act as a CA, with
412  * remainingCAs CAs left in this chain.  Updates chainConstraints with the
413  * element's constraints, if:
414  * 1. chainConstraints doesn't have a path length constraint, or
415  * 2. element's path length constraint is smaller than chainConstraints's
416  * Sets *pathLengthConstraintViolated to TRUE if a path length violation
417  * occurs.
418  * Returns TRUE if the element can be a CA, and the length of the remaining
419  * chain is valid.
420  */
421 static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
422  CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
423  BOOL *pathLengthConstraintViolated)
424 {
425     BOOL validBasicConstraints;
426     CERT_BASIC_CONSTRAINTS2_INFO constraints;
427
428     if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
429      &constraints, TRUE)))
430     {
431         if (!constraints.fCA)
432         {
433             TRACE("chain element %d can't be a CA\n", remainingCAs + 1);
434             validBasicConstraints = FALSE;
435         }
436         else if (constraints.fPathLenConstraint)
437         {
438             /* If the element has path length constraints, they apply to the
439              * entire remaining chain.
440              */
441             if (!chainConstraints->fPathLenConstraint ||
442              constraints.dwPathLenConstraint <
443              chainConstraints->dwPathLenConstraint)
444             {
445                 TRACE("setting path length constraint to %d\n",
446                  chainConstraints->dwPathLenConstraint);
447                 chainConstraints->fPathLenConstraint = TRUE;
448                 chainConstraints->dwPathLenConstraint =
449                  constraints.dwPathLenConstraint;
450             }
451         }
452     }
453     if (chainConstraints->fPathLenConstraint &&
454      remainingCAs > chainConstraints->dwPathLenConstraint)
455     {
456         TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs,
457          chainConstraints->dwPathLenConstraint);
458         validBasicConstraints = FALSE;
459         *pathLengthConstraintViolated = TRUE;
460     }
461     return validBasicConstraints;
462 }
463
464 static BOOL url_matches(LPCWSTR constraint, LPCWSTR name,
465  DWORD *trustErrorStatus)
466 {
467     BOOL match = FALSE;
468
469     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
470
471     if (!constraint)
472         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
473     else if (!name)
474         ; /* no match */
475     else if (constraint[0] == '.')
476     {
477         if (lstrlenW(name) > lstrlenW(constraint))
478             match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
479              constraint);
480     }
481     else
482         match = !lstrcmpiW(constraint, name);
483     return match;
484 }
485
486 static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name,
487  DWORD *trustErrorStatus)
488 {
489     BOOL match = FALSE;
490     LPCWSTR at;
491
492     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
493
494     if (!constraint)
495         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
496     else if (!name)
497         ; /* no match */
498     else if ((at = strchrW(constraint, '@')))
499         match = !lstrcmpiW(constraint, name);
500     else
501     {
502         if ((at = strchrW(name, '@')))
503             match = url_matches(constraint, at + 1, trustErrorStatus);
504         else
505             match = !lstrcmpiW(constraint, name);
506     }
507     return match;
508 }
509
510 static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name,
511  DWORD *trustErrorStatus)
512 {
513     BOOL match = FALSE;
514
515     TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
516
517     if (!constraint)
518         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
519     else if (!name)
520         ; /* no match */
521     else if (lstrlenW(name) >= lstrlenW(constraint))
522         match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
523          constraint);
524     else
525         ; /* name is too short, no match */
526     return match;
527 }
528
529 static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint,
530  const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus)
531 {
532     BOOL match = FALSE;
533
534     TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData,
535      name->cbData, name->pbData);
536
537     if (constraint->cbData != sizeof(DWORD) * 2)
538         *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
539     else if (name->cbData == sizeof(DWORD))
540     {
541         DWORD subnet, mask, addr;
542
543         memcpy(&subnet, constraint->pbData, sizeof(subnet));
544         memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask));
545         memcpy(&addr, name->pbData, sizeof(addr));
546         /* These are really in big-endian order, but for equality matching we
547          * don't need to swap to host order
548          */
549         match = (subnet & mask) == (addr & mask);
550     }
551     else
552         ; /* name is wrong size, no match */
553     return match;
554 }
555
556 static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint,
557  const CERT_ALT_NAME_INFO *subjectName, DWORD *trustErrorStatus,
558  DWORD errorIfFound, DWORD errorIfNotFound)
559 {
560     DWORD i;
561     BOOL defined = FALSE, match = FALSE;
562
563     for (i = 0; i < subjectName->cAltEntry; i++)
564     {
565         if (subjectName->rgAltEntry[i].dwAltNameChoice ==
566          constraint->dwAltNameChoice)
567         {
568             defined = TRUE;
569             switch (constraint->dwAltNameChoice)
570             {
571             case CERT_ALT_NAME_RFC822_NAME:
572                 match = rfc822_name_matches(constraint->u.pwszURL,
573                  subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
574                 break;
575             case CERT_ALT_NAME_DNS_NAME:
576                 match = dns_name_matches(constraint->u.pwszURL,
577                  subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
578                 break;
579             case CERT_ALT_NAME_URL:
580                 match = url_matches(constraint->u.pwszURL,
581                  subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
582                 break;
583             case CERT_ALT_NAME_IP_ADDRESS:
584                 match = ip_address_matches(&constraint->u.IPAddress,
585                  &subjectName->rgAltEntry[i].u.IPAddress, trustErrorStatus);
586                 break;
587             case CERT_ALT_NAME_DIRECTORY_NAME:
588             default:
589                 ERR("name choice %d unsupported in this context\n",
590                  constraint->dwAltNameChoice);
591                 *trustErrorStatus |=
592                  CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
593             }
594         }
595     }
596     /* Microsoft's implementation of name constraint checking appears at odds
597      * with RFC 3280:
598      * According to MSDN, CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT is set
599      * when a name constraint is present, but that name form is not defined in
600      * the end certificate.  According to RFC 3280, "if no name of the type is
601      * in the certificate, the name is acceptable."
602      * I follow Microsoft here.
603      */
604     if (!defined)
605         *trustErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT;
606     *trustErrorStatus |= match ? errorIfFound : errorIfNotFound;
607 }
608
609 static void CRYPT_CheckNameConstraints(
610  const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
611  DWORD *trustErrorStatus)
612 {
613     /* If there aren't any existing constraints, don't bother checking */
614     if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree)
615     {
616         CERT_EXTENSION *ext;
617
618         if ((ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, cert->cExtension,
619          cert->rgExtension)))
620         {
621             CERT_ALT_NAME_INFO *subjectName;
622             DWORD size;
623
624             if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
625              ext->Value.pbData, ext->Value.cbData,
626              CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
627              &subjectName, &size))
628             {
629                 DWORD i;
630
631                 for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
632                     CRYPT_FindMatchingNameEntry(
633                      &nameConstraints->rgExcludedSubtree[i].Base, subjectName,
634                      trustErrorStatus,
635                      CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, 0);
636                 for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
637                     CRYPT_FindMatchingNameEntry(
638                      &nameConstraints->rgPermittedSubtree[i].Base, subjectName,
639                      trustErrorStatus,
640                      0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT);
641                 LocalFree(subjectName);
642             }
643         }
644         else
645         {
646             /* See above comment on CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT.
647              * I match Microsoft's implementation here as well.
648              */
649             *trustErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT;
650             if (nameConstraints->cPermittedSubtree)
651                 *trustErrorStatus |=
652                  CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
653             if (nameConstraints->cExcludedSubtree)
654                 *trustErrorStatus |=
655                  CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
656         }
657     }
658 }
659
660 /* Gets cert's name constraints, if any.  Free with LocalFree. */
661 static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert)
662 {
663     CERT_NAME_CONSTRAINTS_INFO *info = NULL;
664
665     CERT_EXTENSION *ext;
666
667     if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension,
668      cert->rgExtension)))
669     {
670         DWORD size;
671
672         CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
673          ext->Value.pbData, ext->Value.cbData,
674          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info,
675          &size);
676     }
677     return info;
678 }
679
680 static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
681 {
682     int i, j;
683
684     /* Microsoft's implementation appears to violate RFC 3280:  according to
685      * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's
686      * name constraint is violated in the end cert.  According to RFC 3280,
687      * the constraints should be checked against every subsequent certificate
688      * in the chain, not just the end cert.
689      * Microsoft's implementation also sets the name constraint errors on the
690      * certs whose constraints were violated, not on the certs that violated
691      * them.
692      * In order to be error-compatible with Microsoft's implementation, while
693      * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name
694      * constraints.
695      */
696     for (i = chain->cElement - 1; i > 0; i--)
697     {
698         CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
699
700         if ((nameConstraints = CRYPT_GetNameConstraints(
701          chain->rgpElement[i]->pCertContext->pCertInfo)))
702         {
703             for (j = i - 1; j >= 0; j--)
704             {
705                 DWORD errorStatus = 0;
706
707                 /* According to RFC 3280, self-signed certs don't have name
708                  * constraints checked unless they're the end cert.
709                  */
710                 if (j == 0 || !CRYPT_IsCertificateSelfSigned(
711                  chain->rgpElement[j]->pCertContext))
712                 {
713                     CRYPT_CheckNameConstraints(nameConstraints,
714                      chain->rgpElement[i]->pCertContext->pCertInfo,
715                      &errorStatus);
716                     chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
717                      errorStatus;
718                 }
719             }
720             LocalFree(nameConstraints);
721         }
722     }
723 }
724
725 static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
726  PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
727 {
728     PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1];
729     int i;
730     BOOL pathLengthConstraintViolated = FALSE;
731     CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 };
732
733     for (i = chain->cElement - 1; i >= 0; i--)
734     {
735         if (CertVerifyTimeValidity(time,
736          chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
737             chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
738              CERT_TRUST_IS_NOT_TIME_VALID;
739         if (i != 0)
740         {
741             /* Check the signature of the cert this issued */
742             if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
743              CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
744              (void *)chain->rgpElement[i - 1]->pCertContext,
745              CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
746              (void *)chain->rgpElement[i]->pCertContext, 0, NULL))
747                 chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |=
748                  CERT_TRUST_IS_NOT_SIGNATURE_VALID;
749             /* Once a path length constraint has been violated, every remaining
750              * CA cert's basic constraints is considered invalid.
751              */
752             if (pathLengthConstraintViolated)
753                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
754                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
755             else if (!CRYPT_CheckBasicConstraintsForCA(
756              chain->rgpElement[i]->pCertContext, &constraints, i - 1,
757              &pathLengthConstraintViolated))
758                 chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
759                  CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
760             else if (constraints.fPathLenConstraint &&
761              constraints.dwPathLenConstraint)
762             {
763                 /* This one's valid - decrement max length */
764                 constraints.dwPathLenConstraint--;
765             }
766         }
767         /* FIXME: check valid usages */
768         CRYPT_CombineTrustStatus(&chain->TrustStatus,
769          &chain->rgpElement[i]->TrustStatus);
770     }
771     CRYPT_CheckChainNameConstraints(chain);
772     if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext))
773     {
774         rootElement->TrustStatus.dwInfoStatus |=
775          CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
776         CRYPT_CheckRootCert(engine->hRoot, rootElement);
777     }
778     /* FIXME: check revocation of every cert with CertVerifyRevocation */
779     CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
780 }
781
782 static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject,
783  PCCERT_CONTEXT prevIssuer, DWORD *infoStatus)
784 {
785     PCCERT_CONTEXT issuer = NULL;
786     PCERT_EXTENSION ext;
787     DWORD size;
788
789     *infoStatus = 0;
790     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
791      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
792     {
793         CERT_AUTHORITY_KEY_ID_INFO *info;
794         BOOL ret;
795
796         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
797          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
798          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
799          &info, &size);
800         if (ret)
801         {
802             CERT_ID id;
803
804             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
805             {
806                 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
807                 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
808                  sizeof(CERT_NAME_BLOB));
809                 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
810                  &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
811                 issuer = CertFindCertificateInStore(store,
812                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
813                  prevIssuer);
814                 if (issuer)
815                     *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
816             }
817             else if (info->KeyId.cbData)
818             {
819                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
820                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
821                 issuer = CertFindCertificateInStore(store,
822                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
823                  prevIssuer);
824                 if (issuer)
825                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
826             }
827             LocalFree(info);
828         }
829     }
830     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
831      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
832     {
833         CERT_AUTHORITY_KEY_ID2_INFO *info;
834         BOOL ret;
835
836         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
837          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
838          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
839          &info, &size);
840         if (ret)
841         {
842             CERT_ID id;
843
844             if (info->AuthorityCertIssuer.cAltEntry &&
845              info->AuthorityCertSerialNumber.cbData)
846             {
847                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
848                 DWORD i;
849
850                 for (i = 0; !directoryName &&
851                  i < info->AuthorityCertIssuer.cAltEntry; i++)
852                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
853                      == CERT_ALT_NAME_DIRECTORY_NAME)
854                         directoryName =
855                          &info->AuthorityCertIssuer.rgAltEntry[i];
856                 if (directoryName)
857                 {
858                     id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
859                     memcpy(&id.u.IssuerSerialNumber.Issuer,
860                      &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
861                     memcpy(&id.u.IssuerSerialNumber.SerialNumber,
862                      &info->AuthorityCertSerialNumber,
863                      sizeof(CRYPT_INTEGER_BLOB));
864                     issuer = CertFindCertificateInStore(store,
865                      subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
866                      prevIssuer);
867                     if (issuer)
868                         *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
869                 }
870                 else
871                     FIXME("no supported name type in authority key id2\n");
872             }
873             else if (info->KeyId.cbData)
874             {
875                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
876                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
877                 issuer = CertFindCertificateInStore(store,
878                  subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
879                  prevIssuer);
880                 if (issuer)
881                     *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
882             }
883             LocalFree(info);
884         }
885     }
886     else
887     {
888         issuer = CertFindCertificateInStore(store,
889          subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
890          &subject->pCertInfo->Issuer, prevIssuer);
891         if (issuer)
892             *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
893     }
894     return issuer;
895 }
896
897 /* Builds a simple chain by finding an issuer for the last cert in the chain,
898  * until reaching a self-signed cert, or until no issuer can be found.
899  */
900 static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
901  HCERTSTORE world, PCERT_SIMPLE_CHAIN chain)
902 {
903     BOOL ret = TRUE;
904     PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext;
905
906     while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
907      !CRYPT_IsCertificateSelfSigned(cert))
908     {
909         DWORD infoStatus;
910         PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL, &infoStatus);
911
912         if (issuer)
913         {
914             ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, infoStatus);
915             cert = issuer;
916         }
917         else
918         {
919             TRACE("Couldn't find issuer, halting chain creation\n");
920             break;
921         }
922     }
923     return ret;
924 }
925
926 static BOOL CRYPT_GetSimpleChainForCert(PCertificateChainEngine engine,
927  HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime,
928  PCERT_SIMPLE_CHAIN *ppChain)
929 {
930     BOOL ret = FALSE;
931     PCERT_SIMPLE_CHAIN chain;
932
933     TRACE("(%p, %p, %p, %p)\n", engine, world, cert, pTime);
934
935     chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
936     if (chain)
937     {
938         memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
939         chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
940         ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
941         if (ret)
942         {
943             ret = CRYPT_BuildSimpleChain(engine, world, chain);
944             if (ret)
945                 CRYPT_CheckSimpleChain(engine, chain, pTime);
946         }
947         if (!ret)
948         {
949             CRYPT_FreeSimpleChain(chain);
950             chain = NULL;
951         }
952         *ppChain = chain;
953     }
954     return ret;
955 }
956
957 static BOOL CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine,
958  PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
959  PCertificateChain *ppChain)
960 {
961     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
962     PCERT_SIMPLE_CHAIN simpleChain = NULL;
963     HCERTSTORE world;
964     BOOL ret;
965
966     world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
967      CERT_STORE_CREATE_NEW_FLAG, NULL);
968     CertAddStoreToCollection(world, engine->hWorld, 0, 0);
969     if (hAdditionalStore)
970         CertAddStoreToCollection(world, hAdditionalStore, 0, 0);
971     /* FIXME: only simple chains are supported for now, as CTLs aren't
972      * supported yet.
973      */
974     if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime,
975      &simpleChain)))
976     {
977         PCertificateChain chain = CryptMemAlloc(sizeof(CertificateChain));
978
979         if (chain)
980         {
981             chain->ref = 1;
982             chain->world = world;
983             chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
984             memcpy(&chain->context.TrustStatus, &simpleChain->TrustStatus,
985              sizeof(CERT_TRUST_STATUS));
986             chain->context.cChain = 1;
987             chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN));
988             chain->context.rgpChain[0] = simpleChain;
989             chain->context.cLowerQualityChainContext = 0;
990             chain->context.rgpLowerQualityChainContext = NULL;
991             chain->context.fHasRevocationFreshnessTime = FALSE;
992             chain->context.dwRevocationFreshnessTime = 0;
993         }
994         else
995             ret = FALSE;
996         *ppChain = chain;
997     }
998     return ret;
999 }
1000
1001 /* Makes and returns a copy of chain, up to and including element iElement. */
1002 static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement(
1003  PCERT_SIMPLE_CHAIN chain, DWORD iElement)
1004 {
1005     PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
1006
1007     if (copy)
1008     {
1009         memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN));
1010         copy->cbSize = sizeof(CERT_SIMPLE_CHAIN);
1011         copy->rgpElement =
1012          CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
1013         if (copy->rgpElement)
1014         {
1015             DWORD i;
1016             BOOL ret = TRUE;
1017
1018             memset(copy->rgpElement, 0,
1019              (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
1020             for (i = 0; ret && i <= iElement; i++)
1021             {
1022                 PCERT_CHAIN_ELEMENT element =
1023                  CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
1024
1025                 if (element)
1026                 {
1027                     memcpy(element, chain->rgpElement[i],
1028                      sizeof(CERT_CHAIN_ELEMENT));
1029                     element->pCertContext = CertDuplicateCertificateContext(
1030                      chain->rgpElement[i]->pCertContext);
1031                     /* Reset the trust status of the copied element, it'll get
1032                      * rechecked after the new chain is done.
1033                      */
1034                     memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
1035                     copy->rgpElement[copy->cElement++] = element;
1036                 }
1037                 else
1038                     ret = FALSE;
1039             }
1040             if (!ret)
1041             {
1042                 for (i = 0; i <= iElement; i++)
1043                     CryptMemFree(copy->rgpElement[i]);
1044                 CryptMemFree(copy->rgpElement);
1045                 CryptMemFree(copy);
1046                 copy = NULL;
1047             }
1048         }
1049         else
1050         {
1051             CryptMemFree(copy);
1052             copy = NULL;
1053         }
1054     }
1055     return copy;
1056 }
1057
1058 static void CRYPT_FreeLowerQualityChains(PCertificateChain chain)
1059 {
1060     DWORD i;
1061
1062     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
1063         CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]);
1064     CryptMemFree(chain->context.rgpLowerQualityChainContext);
1065 }
1066
1067 static void CRYPT_FreeChainContext(PCertificateChain chain)
1068 {
1069     DWORD i;
1070
1071     CRYPT_FreeLowerQualityChains(chain);
1072     for (i = 0; i < chain->context.cChain; i++)
1073         CRYPT_FreeSimpleChain(chain->context.rgpChain[i]);
1074     CryptMemFree(chain->context.rgpChain);
1075     CertCloseStore(chain->world, 0);
1076     CryptMemFree(chain);
1077 }
1078
1079 /* Makes and returns a copy of chain, up to and including element iElement of
1080  * simple chain iChain.
1081  */
1082 static PCertificateChain CRYPT_CopyChainToElement(PCertificateChain chain,
1083  DWORD iChain, DWORD iElement)
1084 {
1085     PCertificateChain copy = CryptMemAlloc(sizeof(CertificateChain));
1086
1087     if (copy)
1088     {
1089         copy->ref = 1;
1090         copy->world = CertDuplicateStore(chain->world);
1091         copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
1092         /* Leave the trust status of the copied chain unset, it'll get
1093          * rechecked after the new chain is done.
1094          */
1095         memset(&copy->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
1096         copy->context.cLowerQualityChainContext = 0;
1097         copy->context.rgpLowerQualityChainContext = NULL;
1098         copy->context.fHasRevocationFreshnessTime = FALSE;
1099         copy->context.dwRevocationFreshnessTime = 0;
1100         copy->context.rgpChain = CryptMemAlloc(
1101          (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
1102         if (copy->context.rgpChain)
1103         {
1104             BOOL ret = TRUE;
1105             DWORD i;
1106
1107             memset(copy->context.rgpChain, 0,
1108              (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
1109             if (iChain)
1110             {
1111                 for (i = 0; ret && iChain && i < iChain - 1; i++)
1112                 {
1113                     copy->context.rgpChain[i] =
1114                      CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
1115                      chain->context.rgpChain[i]->cElement - 1);
1116                     if (!copy->context.rgpChain[i])
1117                         ret = FALSE;
1118                 }
1119             }
1120             else
1121                 i = 0;
1122             if (ret)
1123             {
1124                 copy->context.rgpChain[i] =
1125                  CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
1126                  iElement);
1127                 if (!copy->context.rgpChain[i])
1128                     ret = FALSE;
1129             }
1130             if (!ret)
1131             {
1132                 CRYPT_FreeChainContext(copy);
1133                 copy = NULL;
1134             }
1135             else
1136                 copy->context.cChain = iChain + 1;
1137         }
1138         else
1139         {
1140             CryptMemFree(copy);
1141             copy = NULL;
1142         }
1143     }
1144     return copy;
1145 }
1146
1147 static PCertificateChain CRYPT_BuildAlternateContextFromChain(
1148  HCERTCHAINENGINE hChainEngine, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
1149  PCertificateChain chain)
1150 {
1151     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
1152     PCertificateChain alternate;
1153
1154     TRACE("(%p, %p, %p, %p)\n", hChainEngine, pTime, hAdditionalStore, chain);
1155
1156     /* Always start with the last "lower quality" chain to ensure a consistent
1157      * order of alternate creation:
1158      */
1159     if (chain->context.cLowerQualityChainContext)
1160         chain = (PCertificateChain)chain->context.rgpLowerQualityChainContext[
1161          chain->context.cLowerQualityChainContext - 1];
1162     /* A chain with only one element can't have any alternates */
1163     if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1)
1164         alternate = NULL;
1165     else
1166     {
1167         DWORD i, j, infoStatus;
1168         PCCERT_CONTEXT alternateIssuer = NULL;
1169
1170         alternate = NULL;
1171         for (i = 0; !alternateIssuer && i < chain->context.cChain; i++)
1172             for (j = 0; !alternateIssuer &&
1173              j < chain->context.rgpChain[i]->cElement - 1; j++)
1174             {
1175                 PCCERT_CONTEXT subject =
1176                  chain->context.rgpChain[i]->rgpElement[j]->pCertContext;
1177                 PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext(
1178                  chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext);
1179
1180                 alternateIssuer = CRYPT_GetIssuer(prevIssuer->hCertStore,
1181                  subject, prevIssuer, &infoStatus);
1182             }
1183         if (alternateIssuer)
1184         {
1185             i--;
1186             j--;
1187             alternate = CRYPT_CopyChainToElement(chain, i, j);
1188             if (alternate)
1189             {
1190                 BOOL ret = CRYPT_AddCertToSimpleChain(engine,
1191                  alternate->context.rgpChain[i], alternateIssuer, infoStatus);
1192
1193                 if (ret)
1194                 {
1195                     ret = CRYPT_BuildSimpleChain(engine, alternate->world,
1196                      alternate->context.rgpChain[i]);
1197                     if (ret)
1198                         CRYPT_CheckSimpleChain(engine,
1199                          alternate->context.rgpChain[i], pTime);
1200                     CRYPT_CombineTrustStatus(&alternate->context.TrustStatus,
1201                      &alternate->context.rgpChain[i]->TrustStatus);
1202                 }
1203                 if (!ret)
1204                 {
1205                     CRYPT_FreeChainContext(alternate);
1206                     alternate = NULL;
1207                 }
1208             }
1209         }
1210     }
1211     TRACE("%p\n", alternate);
1212     return alternate;
1213 }
1214
1215 #define CHAIN_QUALITY_SIGNATURE_VALID 8
1216 #define CHAIN_QUALITY_TIME_VALID      4
1217 #define CHAIN_QUALITY_COMPLETE_CHAIN  2
1218 #define CHAIN_QUALITY_TRUSTED_ROOT    1
1219
1220 #define CHAIN_QUALITY_HIGHEST \
1221  CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
1222  CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT
1223
1224 #define IS_TRUST_ERROR_SET(TrustStatus, bits) \
1225  (TrustStatus)->dwErrorStatus & (bits)
1226
1227 static DWORD CRYPT_ChainQuality(PCertificateChain chain)
1228 {
1229     DWORD quality = CHAIN_QUALITY_HIGHEST;
1230
1231     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
1232      CERT_TRUST_IS_UNTRUSTED_ROOT))
1233         quality &= ~CHAIN_QUALITY_TRUSTED_ROOT;
1234     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
1235      CERT_TRUST_IS_PARTIAL_CHAIN))
1236     if (chain->context.TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
1237         quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN;
1238     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
1239      CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED))
1240         quality &= ~CHAIN_QUALITY_TIME_VALID;
1241     if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
1242      CERT_TRUST_IS_NOT_SIGNATURE_VALID))
1243         quality &= ~CHAIN_QUALITY_SIGNATURE_VALID;
1244     return quality;
1245 }
1246
1247 /* Chooses the highest quality chain among chain and its "lower quality"
1248  * alternate chains.  Returns the highest quality chain, with all other
1249  * chains as lower quality chains of it.
1250  */
1251 static PCertificateChain CRYPT_ChooseHighestQualityChain(
1252  PCertificateChain chain)
1253 {
1254     DWORD i;
1255
1256     /* There are always only two chains being considered:  chain, and an
1257      * alternate at chain->rgpLowerQualityChainContext[i].  If the alternate
1258      * has a higher quality than chain, the alternate gets assigned the lower
1259      * quality contexts, with chain taking the alternate's place among the
1260      * lower quality contexts.
1261      */
1262     for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
1263     {
1264         PCertificateChain alternate =
1265          (PCertificateChain)chain->context.rgpLowerQualityChainContext[i];
1266
1267         if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain))
1268         {
1269             alternate->context.cLowerQualityChainContext =
1270              chain->context.cLowerQualityChainContext;
1271             alternate->context.rgpLowerQualityChainContext =
1272              chain->context.rgpLowerQualityChainContext;
1273             alternate->context.rgpLowerQualityChainContext[i] =
1274              (PCCERT_CHAIN_CONTEXT)chain;
1275             chain = alternate;
1276         }
1277     }
1278     return chain;
1279 }
1280
1281 static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain,
1282  PCertificateChain alternate)
1283 {
1284     BOOL ret;
1285
1286     if (chain->context.cLowerQualityChainContext)
1287         chain->context.rgpLowerQualityChainContext =
1288          CryptMemRealloc(chain->context.rgpLowerQualityChainContext,
1289          (chain->context.cLowerQualityChainContext + 1) *
1290          sizeof(PCCERT_CHAIN_CONTEXT));
1291     else
1292         chain->context.rgpLowerQualityChainContext =
1293          CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT));
1294     if (chain->context.rgpLowerQualityChainContext)
1295     {
1296         chain->context.rgpLowerQualityChainContext[
1297          chain->context.cLowerQualityChainContext++] =
1298          (PCCERT_CHAIN_CONTEXT)alternate;
1299         ret = TRUE;
1300     }
1301     else
1302         ret = FALSE;
1303     return ret;
1304 }
1305
1306 typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS {
1307     DWORD            cbSize;
1308     CERT_USAGE_MATCH RequestedUsage;
1309 } CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS;
1310
1311 typedef struct _CERT_CHAIN_PARA_EXTRA_FIELDS {
1312     DWORD            cbSize;
1313     CERT_USAGE_MATCH RequestedUsage;
1314     CERT_USAGE_MATCH RequestedIssuancePolicy;
1315     DWORD            dwUrlRetrievalTimeout;
1316     BOOL             fCheckRevocationFreshnessTime;
1317     DWORD            dwRevocationFreshnessTime;
1318 } CERT_CHAIN_PARA_EXTRA_FIELDS, *PCERT_CHAIN_PARA_EXTRA_FIELDS;
1319
1320 BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
1321  PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
1322  PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
1323  PCCERT_CHAIN_CONTEXT* ppChainContext)
1324 {
1325     BOOL ret;
1326     PCertificateChain chain = NULL;
1327
1328     TRACE("(%p, %p, %p, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext,
1329      pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, ppChainContext);
1330
1331     if (ppChainContext)
1332         *ppChainContext = NULL;
1333     if (!pChainPara)
1334     {
1335         SetLastError(E_INVALIDARG);
1336         return FALSE;
1337     }
1338     if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)
1339     {
1340         SetLastError(ERROR_INVALID_DATA);
1341         return FALSE;
1342     }
1343     if (!hChainEngine)
1344         hChainEngine = CRYPT_GetDefaultChainEngine();
1345     /* FIXME: what about HCCE_LOCAL_MACHINE? */
1346     /* FIXME: pChainPara is for now ignored */
1347     ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime,
1348      hAdditionalStore, &chain);
1349     if (ret)
1350     {
1351         PCertificateChain alternate = NULL;
1352
1353         do {
1354             alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine,
1355              pTime, hAdditionalStore, chain);
1356
1357             /* Alternate contexts are added as "lower quality" contexts of
1358              * chain, to avoid loops in alternate chain creation.
1359              * The highest-quality chain is chosen at the end.
1360              */
1361             if (alternate)
1362                 ret = CRYPT_AddAlternateChainToChain(chain, alternate);
1363         } while (ret && alternate);
1364         chain = CRYPT_ChooseHighestQualityChain(chain);
1365         if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
1366         {
1367             CRYPT_FreeLowerQualityChains(chain);
1368             chain->context.cLowerQualityChainContext = 0;
1369             chain->context.rgpLowerQualityChainContext = NULL;
1370         }
1371         if (ppChainContext)
1372             *ppChainContext = (PCCERT_CHAIN_CONTEXT)chain;
1373         else
1374             CertFreeCertificateChain((PCCERT_CHAIN_CONTEXT)chain);
1375     }
1376     TRACE("returning %d\n", ret);
1377     return ret;
1378 }
1379
1380 PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain(
1381  PCCERT_CHAIN_CONTEXT pChainContext)
1382 {
1383     PCertificateChain chain = (PCertificateChain)pChainContext;
1384
1385     TRACE("(%p)\n", pChainContext);
1386
1387     if (chain)
1388         InterlockedIncrement(&chain->ref);
1389     return pChainContext;
1390 }
1391
1392 VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext)
1393 {
1394     PCertificateChain chain = (PCertificateChain)pChainContext;
1395
1396     TRACE("(%p)\n", pChainContext);
1397
1398     if (chain)
1399     {
1400         if (InterlockedDecrement(&chain->ref) == 0)
1401             CRYPT_FreeChainContext(chain);
1402     }
1403 }
1404
1405 static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error,
1406  LONG *iChain, LONG *iElement)
1407 {
1408     DWORD i, j;
1409
1410     for (i = 0; i < chain->cChain; i++)
1411         for (j = 0; j < chain->rgpChain[i]->cElement; j++)
1412             if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus &
1413              error)
1414             {
1415                 *iChain = i;
1416                 *iElement = j;
1417                 return;
1418             }
1419 }
1420
1421 static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID,
1422  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
1423  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
1424 {
1425     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
1426     if (pChainContext->TrustStatus.dwErrorStatus &
1427      CERT_TRUST_IS_NOT_SIGNATURE_VALID)
1428     {
1429         pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
1430         find_element_with_error(pChainContext,
1431          CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
1432          &pPolicyStatus->lElementIndex);
1433     }
1434     else if (pChainContext->TrustStatus.dwErrorStatus &
1435      CERT_TRUST_IS_UNTRUSTED_ROOT)
1436     {
1437         pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
1438         find_element_with_error(pChainContext,
1439          CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
1440          &pPolicyStatus->lElementIndex);
1441     }
1442     else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
1443     {
1444         pPolicyStatus->dwError = CERT_E_CHAINING;
1445         find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC,
1446          &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex);
1447         /* For a cyclic chain, which element is a cycle isn't meaningful */
1448         pPolicyStatus->lElementIndex = -1;
1449     }
1450     return TRUE;
1451 }
1452
1453 static BYTE msTestPubKey1[] = {
1454 0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9,
1455 0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7,
1456 0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f,
1457 0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10,
1458 0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
1459 static BYTE msTestPubKey2[] = {
1460 0x30,0x48,0x02,0x41,0x00,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,
1461 0xd9,0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,
1462 0xf7,0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,
1463 0x5f,0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,
1464 0x10,0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
1465 static BYTE msTestPubKey3[] = {
1466 0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5,
1467 0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8,
1468 0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6,
1469 0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18,
1470 0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 };
1471
1472 static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID,
1473  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
1474  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
1475 {
1476     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
1477      pPolicyStatus);
1478
1479     if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT)
1480     {
1481         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
1482         BOOL isMSTestRoot = FALSE;
1483         PCCERT_CONTEXT failingCert =
1484          pChainContext->rgpChain[pPolicyStatus->lChainIndex]->
1485          rgpElement[pPolicyStatus->lElementIndex]->pCertContext;
1486         DWORD i;
1487         CRYPT_DATA_BLOB keyBlobs[] = {
1488          { sizeof(msTestPubKey1), msTestPubKey1 },
1489          { sizeof(msTestPubKey2), msTestPubKey2 },
1490          { sizeof(msTestPubKey3), msTestPubKey3 },
1491         };
1492
1493         /* Check whether the root is an MS test root */
1494         for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
1495          i++)
1496         {
1497             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
1498             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
1499             if (CertComparePublicKeyInfo(
1500              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1501              &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
1502                 isMSTestRoot = TRUE;
1503         }
1504         if (isMSTestRoot)
1505             pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT;
1506     }
1507     return ret;
1508 }
1509
1510 static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID,
1511  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
1512  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
1513 {
1514     pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
1515     if (pChainContext->TrustStatus.dwErrorStatus &
1516      CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
1517     {
1518         pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS;
1519         find_element_with_error(pChainContext,
1520          CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex,
1521          &pPolicyStatus->lElementIndex);
1522     }
1523     return TRUE;
1524 }
1525
1526 static BYTE msPubKey1[] = {
1527 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
1528 0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
1529 0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29,
1530 0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16,
1531 0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60,
1532 0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5,
1533 0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d,
1534 0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61,
1535 0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e,
1536 0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94,
1537 0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb,
1538 0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a,
1539 0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d,
1540 0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb,
1541 0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08,
1542 0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43,
1543 0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf,
1544 0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 };
1545 static BYTE msPubKey2[] = {
1546 0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6,
1547 0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25,
1548 0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2,
1549 0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54,
1550 0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62,
1551 0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a,
1552 0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7,
1553 0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84,
1554 0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9,
1555 0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91,
1556 0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52,
1557 0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80,
1558 0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18,
1559 0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07,
1560 0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef,
1561 0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0,
1562 0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30,
1563 0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 };
1564 static BYTE msPubKey3[] = {
1565 0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4,
1566 0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7,
1567 0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94,
1568 0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04,
1569 0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d,
1570 0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09,
1571 0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae,
1572 0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7,
1573 0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f,
1574 0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94,
1575 0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d,
1576 0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05,
1577 0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e,
1578 0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d,
1579 0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b,
1580 0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67,
1581 0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08,
1582 0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5,
1583 0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64,
1584 0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38,
1585 0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0,
1586 0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9,
1587 0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28,
1588 0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc,
1589 0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45,
1590 0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde,
1591 0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04,
1592 0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89,
1593 0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11,
1594 0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32,
1595 0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40,
1596 0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41,
1597 0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1,
1598 0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5,
1599 0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00,
1600 0x01 };
1601
1602 static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
1603  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
1604  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
1605 {
1606     BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
1607      pPolicyStatus);
1608
1609     if (ret && !pPolicyStatus->dwError)
1610     {
1611         CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
1612         BOOL isMSRoot = FALSE;
1613         DWORD i;
1614         CRYPT_DATA_BLOB keyBlobs[] = {
1615          { sizeof(msPubKey1), msPubKey1 },
1616          { sizeof(msPubKey2), msPubKey2 },
1617          { sizeof(msPubKey3), msPubKey3 },
1618         };
1619         PCERT_SIMPLE_CHAIN rootChain =
1620          pChainContext->rgpChain[pChainContext->cChain -1 ];
1621         PCCERT_CONTEXT root =
1622          rootChain->rgpElement[rootChain->cElement - 1]->pCertContext;
1623
1624         for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
1625          i++)
1626         {
1627             msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
1628             msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
1629             if (CertComparePublicKeyInfo(
1630              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1631              &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
1632                 isMSRoot = TRUE;
1633         }
1634         if (isMSRoot)
1635             pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0;
1636     }
1637     return ret;
1638 }
1639
1640 typedef BOOL (WINAPI *CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID,
1641  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
1642  PCERT_CHAIN_POLICY_STATUS pPolicyStatus);
1643
1644 BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID,
1645  PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
1646  PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
1647 {
1648     static HCRYPTOIDFUNCSET set = NULL;
1649     BOOL ret = FALSE;
1650     CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL;
1651     HCRYPTOIDFUNCADDR hFunc = NULL;
1652
1653     TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext,
1654      pPolicyPara, pPolicyStatus);
1655
1656     if (!HIWORD(szPolicyOID))
1657     {
1658         switch (LOWORD(szPolicyOID))
1659         {
1660         case (int)CERT_CHAIN_POLICY_BASE:
1661             verifyPolicy = verify_base_policy;
1662             break;
1663         case (int)CERT_CHAIN_POLICY_AUTHENTICODE:
1664             verifyPolicy = verify_authenticode_policy;
1665             break;
1666         case (int)CERT_CHAIN_POLICY_BASIC_CONSTRAINTS:
1667             verifyPolicy = verify_basic_constraints_policy;
1668             break;
1669         case (int)CERT_CHAIN_POLICY_MICROSOFT_ROOT:
1670             verifyPolicy = verify_ms_root_policy;
1671             break;
1672         default:
1673             FIXME("unimplemented for %d\n", LOWORD(szPolicyOID));
1674         }
1675     }
1676     if (!verifyPolicy)
1677     {
1678         if (!set)
1679             set = CryptInitOIDFunctionSet(
1680              CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0);
1681         CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0,
1682          (void **)&verifyPolicy, hFunc);
1683     }
1684     if (verifyPolicy)
1685         ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara,
1686          pPolicyStatus);
1687     if (hFunc)
1688         CryptFreeOIDFunctionAddress(hFunc, 0);
1689     return ret;
1690 }