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