...

Source file src/crypto/x509/verify_test.go

Documentation: crypto/x509

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package x509
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/ecdsa"
    10  	"crypto/elliptic"
    11  	"crypto/rand"
    12  	"crypto/x509/pkix"
    13  	"encoding/asn1"
    14  	"encoding/pem"
    15  	"errors"
    16  	"fmt"
    17  	"internal/testenv"
    18  	"math/big"
    19  	"os/exec"
    20  	"reflect"
    21  	"runtime"
    22  	"slices"
    23  	"strconv"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  )
    28  
    29  type verifyTest struct {
    30  	name          string
    31  	leaf          string
    32  	intermediates []string
    33  	roots         []string
    34  	currentTime   int64
    35  	dnsName       string
    36  	systemSkip    bool
    37  	systemLax     bool
    38  	keyUsages     []ExtKeyUsage
    39  
    40  	errorCallback  func(*testing.T, error)
    41  	expectedChains [][]string
    42  }
    43  
    44  var verifyTests = []verifyTest{
    45  	{
    46  		name:          "Valid",
    47  		leaf:          googleLeaf,
    48  		intermediates: []string{gtsIntermediate},
    49  		roots:         []string{gtsRoot},
    50  		currentTime:   1677615892,
    51  		dnsName:       "www.google.com",
    52  
    53  		expectedChains: [][]string{
    54  			{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
    55  		},
    56  	},
    57  	{
    58  		name:          "Valid (fqdn)",
    59  		leaf:          googleLeaf,
    60  		intermediates: []string{gtsIntermediate},
    61  		roots:         []string{gtsRoot},
    62  		currentTime:   1677615892,
    63  		dnsName:       "www.google.com.",
    64  
    65  		expectedChains: [][]string{
    66  			{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
    67  		},
    68  	},
    69  	{
    70  		name:          "MixedCase",
    71  		leaf:          googleLeaf,
    72  		intermediates: []string{gtsIntermediate},
    73  		roots:         []string{gtsRoot},
    74  		currentTime:   1677615892,
    75  		dnsName:       "WwW.GooGLE.coM",
    76  
    77  		expectedChains: [][]string{
    78  			{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
    79  		},
    80  	},
    81  	{
    82  		name:          "HostnameMismatch",
    83  		leaf:          googleLeaf,
    84  		intermediates: []string{gtsIntermediate},
    85  		roots:         []string{gtsRoot},
    86  		currentTime:   1677615892,
    87  		dnsName:       "www.example.com",
    88  
    89  		errorCallback: expectHostnameError("certificate is valid for"),
    90  	},
    91  	{
    92  		name:          "IPMissing",
    93  		leaf:          googleLeaf,
    94  		intermediates: []string{gtsIntermediate},
    95  		roots:         []string{gtsRoot},
    96  		currentTime:   1677615892,
    97  		dnsName:       "1.2.3.4",
    98  
    99  		errorCallback: expectHostnameError("doesn't contain any IP SANs"),
   100  	},
   101  	{
   102  		name:          "Expired",
   103  		leaf:          googleLeaf,
   104  		intermediates: []string{gtsIntermediate},
   105  		roots:         []string{gtsRoot},
   106  		currentTime:   1,
   107  		dnsName:       "www.example.com",
   108  
   109  		errorCallback: expectExpired,
   110  	},
   111  	{
   112  		name:        "MissingIntermediate",
   113  		leaf:        googleLeaf,
   114  		roots:       []string{gtsRoot},
   115  		currentTime: 1677615892,
   116  		dnsName:     "www.google.com",
   117  
   118  		// Skip when using systemVerify, since Windows
   119  		// *will* find the missing intermediate cert.
   120  		systemSkip:    true,
   121  		errorCallback: expectAuthorityUnknown,
   122  	},
   123  	{
   124  		name:          "RootInIntermediates",
   125  		leaf:          googleLeaf,
   126  		intermediates: []string{gtsRoot, gtsIntermediate},
   127  		roots:         []string{gtsRoot},
   128  		currentTime:   1677615892,
   129  		dnsName:       "www.google.com",
   130  
   131  		expectedChains: [][]string{
   132  			{"www.google.com", "GTS CA 1C3", "GTS Root R1"},
   133  		},
   134  		// CAPI doesn't build the chain with the duplicated GeoTrust
   135  		// entry so the results don't match.
   136  		systemLax: true,
   137  	},
   138  	{
   139  		name:          "dnssec-exp",
   140  		leaf:          dnssecExpLeaf,
   141  		intermediates: []string{startComIntermediate},
   142  		roots:         []string{startComRoot},
   143  		currentTime:   1302726541,
   144  
   145  		// The StartCom root is not trusted by Windows when the default
   146  		// ServerAuth EKU is requested.
   147  		systemSkip: true,
   148  
   149  		expectedChains: [][]string{
   150  			{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
   151  		},
   152  	},
   153  	{
   154  		name:          "dnssec-exp/AnyEKU",
   155  		leaf:          dnssecExpLeaf,
   156  		intermediates: []string{startComIntermediate},
   157  		roots:         []string{startComRoot},
   158  		currentTime:   1302726541,
   159  		keyUsages:     []ExtKeyUsage{ExtKeyUsageAny},
   160  
   161  		expectedChains: [][]string{
   162  			{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
   163  		},
   164  	},
   165  	{
   166  		name:          "dnssec-exp/RootInIntermediates",
   167  		leaf:          dnssecExpLeaf,
   168  		intermediates: []string{startComIntermediate, startComRoot},
   169  		roots:         []string{startComRoot},
   170  		currentTime:   1302726541,
   171  		systemSkip:    true, // see dnssec-exp test
   172  
   173  		expectedChains: [][]string{
   174  			{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
   175  		},
   176  	},
   177  	{
   178  		name:          "InvalidHash",
   179  		leaf:          googleLeafWithInvalidHash,
   180  		intermediates: []string{gtsIntermediate},
   181  		roots:         []string{gtsRoot},
   182  		currentTime:   1677615892,
   183  		dnsName:       "www.google.com",
   184  
   185  		// The specific error message may not occur when using system
   186  		// verification.
   187  		systemLax:     true,
   188  		errorCallback: expectHashError,
   189  	},
   190  	// EKULeaf tests use an unconstrained chain leading to a leaf certificate
   191  	// with an E-mail Protection EKU but not a Server Auth one, checking that
   192  	// the EKUs on the leaf are enforced.
   193  	{
   194  		name:          "EKULeaf",
   195  		leaf:          smimeLeaf,
   196  		intermediates: []string{smimeIntermediate},
   197  		roots:         []string{smimeRoot},
   198  		currentTime:   1594673418,
   199  
   200  		errorCallback: expectUsageError,
   201  	},
   202  	{
   203  		name:          "EKULeafExplicit",
   204  		leaf:          smimeLeaf,
   205  		intermediates: []string{smimeIntermediate},
   206  		roots:         []string{smimeRoot},
   207  		currentTime:   1594673418,
   208  		keyUsages:     []ExtKeyUsage{ExtKeyUsageServerAuth},
   209  
   210  		errorCallback: expectUsageError,
   211  	},
   212  	{
   213  		name:          "EKULeafValid",
   214  		leaf:          smimeLeaf,
   215  		intermediates: []string{smimeIntermediate},
   216  		roots:         []string{smimeRoot},
   217  		currentTime:   1594673418,
   218  		keyUsages:     []ExtKeyUsage{ExtKeyUsageEmailProtection},
   219  
   220  		expectedChains: [][]string{
   221  			{"CORPORATIVO FICTICIO ACTIVO", "EAEko Herri Administrazioen CA - CA AAPP Vascas (2)", "IZENPE S.A."},
   222  		},
   223  	},
   224  	{
   225  		// Check that a name constrained intermediate works even when
   226  		// it lists multiple constraints.
   227  		name:          "MultipleConstraints",
   228  		leaf:          nameConstraintsLeaf,
   229  		intermediates: []string{nameConstraintsIntermediate1, nameConstraintsIntermediate2},
   230  		roots:         []string{globalSignRoot},
   231  		currentTime:   1382387896,
   232  		dnsName:       "secure.iddl.vt.edu",
   233  
   234  		expectedChains: [][]string{
   235  			{
   236  				"Technology-enhanced Learning and Online Strategies",
   237  				"Virginia Tech Global Qualified Server CA",
   238  				"Trusted Root CA G2",
   239  				"GlobalSign Root CA",
   240  			},
   241  		},
   242  	},
   243  	{
   244  		// Check that SHA-384 intermediates (which are popping up)
   245  		// work.
   246  		name:          "SHA-384",
   247  		leaf:          trustAsiaLeaf,
   248  		intermediates: []string{trustAsiaSHA384Intermediate},
   249  		roots:         []string{digicertRoot},
   250  		currentTime:   1558051200,
   251  		dnsName:       "tm.cn",
   252  
   253  		// CryptoAPI can find alternative validation paths.
   254  		systemLax: true,
   255  
   256  		expectedChains: [][]string{
   257  			{
   258  				"tm.cn",
   259  				"TrustAsia ECC OV TLS Pro CA",
   260  				"DigiCert Global Root CA",
   261  			},
   262  		},
   263  	},
   264  	{
   265  		// Putting a certificate as a root directly should work as a
   266  		// way of saying “exactly this”.
   267  		name:        "LeafInRoots",
   268  		leaf:        selfSigned,
   269  		roots:       []string{selfSigned},
   270  		currentTime: 1471624472,
   271  		dnsName:     "foo.example",
   272  		systemSkip:  true, // does not chain to a system root
   273  
   274  		expectedChains: [][]string{
   275  			{"Acme Co"},
   276  		},
   277  	},
   278  	{
   279  		// Putting a certificate as a root directly should not skip
   280  		// other checks however.
   281  		name:        "LeafInRootsInvalid",
   282  		leaf:        selfSigned,
   283  		roots:       []string{selfSigned},
   284  		currentTime: 1471624472,
   285  		dnsName:     "notfoo.example",
   286  		systemSkip:  true, // does not chain to a system root
   287  
   288  		errorCallback: expectHostnameError("certificate is valid for"),
   289  	},
   290  	{
   291  		// An X.509 v1 certificate should not be accepted as an
   292  		// intermediate.
   293  		name:          "X509v1Intermediate",
   294  		leaf:          x509v1TestLeaf,
   295  		intermediates: []string{x509v1TestIntermediate},
   296  		roots:         []string{x509v1TestRoot},
   297  		currentTime:   1481753183,
   298  		systemSkip:    true, // does not chain to a system root
   299  
   300  		errorCallback: expectNotAuthorizedError,
   301  	},
   302  	{
   303  		name:        "IgnoreCNWithSANs",
   304  		leaf:        ignoreCNWithSANLeaf,
   305  		dnsName:     "foo.example.com",
   306  		roots:       []string{ignoreCNWithSANRoot},
   307  		currentTime: 1486684488,
   308  		systemSkip:  true, // does not chain to a system root
   309  
   310  		errorCallback: expectHostnameError("certificate is not valid for any names"),
   311  	},
   312  	{
   313  		// Test that excluded names are respected.
   314  		name:          "ExcludedNames",
   315  		leaf:          excludedNamesLeaf,
   316  		dnsName:       "bender.local",
   317  		intermediates: []string{excludedNamesIntermediate},
   318  		roots:         []string{excludedNamesRoot},
   319  		currentTime:   1486684488,
   320  		systemSkip:    true, // does not chain to a system root
   321  
   322  		errorCallback: expectNameConstraintsError,
   323  	},
   324  	{
   325  		// Test that unknown critical extensions in a leaf cause a
   326  		// verify error.
   327  		name:          "CriticalExtLeaf",
   328  		leaf:          criticalExtLeafWithExt,
   329  		intermediates: []string{criticalExtIntermediate},
   330  		roots:         []string{criticalExtRoot},
   331  		currentTime:   1486684488,
   332  		systemSkip:    true, // does not chain to a system root
   333  
   334  		errorCallback: expectUnhandledCriticalExtension,
   335  	},
   336  	{
   337  		// Test that unknown critical extensions in an intermediate
   338  		// cause a verify error.
   339  		name:          "CriticalExtIntermediate",
   340  		leaf:          criticalExtLeaf,
   341  		intermediates: []string{criticalExtIntermediateWithExt},
   342  		roots:         []string{criticalExtRoot},
   343  		currentTime:   1486684488,
   344  		systemSkip:    true, // does not chain to a system root
   345  
   346  		errorCallback: expectUnhandledCriticalExtension,
   347  	},
   348  	{
   349  		name:        "ValidCN",
   350  		leaf:        validCNWithoutSAN,
   351  		dnsName:     "foo.example.com",
   352  		roots:       []string{invalidCNRoot},
   353  		currentTime: 1540000000,
   354  		systemSkip:  true, // does not chain to a system root
   355  
   356  		errorCallback: expectHostnameError("certificate relies on legacy Common Name field"),
   357  	},
   358  	{
   359  		// A certificate with an AKID should still chain to a parent without SKID.
   360  		// See Issue 30079.
   361  		name:        "AKIDNoSKID",
   362  		leaf:        leafWithAKID,
   363  		roots:       []string{rootWithoutSKID},
   364  		currentTime: 1550000000,
   365  		dnsName:     "example",
   366  		systemSkip:  true, // does not chain to a system root
   367  
   368  		expectedChains: [][]string{
   369  			{"Acme LLC", "Acme Co"},
   370  		},
   371  	},
   372  	{
   373  		// When there are two parents, one with an incorrect subject but matching SKID
   374  		// and one with a correct subject but missing SKID, the latter should be
   375  		// considered as a possible parent.
   376  		leaf:        leafMatchingAKIDMatchingIssuer,
   377  		roots:       []string{rootMatchingSKIDMismatchingSubject, rootMismatchingSKIDMatchingSubject},
   378  		currentTime: 1550000000,
   379  		dnsName:     "example",
   380  		systemSkip:  true,
   381  
   382  		expectedChains: [][]string{
   383  			{"Leaf", "Root B"},
   384  		},
   385  	},
   386  }
   387  
   388  func expectHostnameError(msg string) func(*testing.T, error) {
   389  	return func(t *testing.T, err error) {
   390  		if _, ok := err.(HostnameError); !ok {
   391  			t.Fatalf("error was not a HostnameError: %v", err)
   392  		}
   393  		if !strings.Contains(err.Error(), msg) {
   394  			t.Fatalf("HostnameError did not contain %q: %v", msg, err)
   395  		}
   396  	}
   397  }
   398  
   399  func expectExpired(t *testing.T, err error) {
   400  	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired {
   401  		t.Fatalf("error was not Expired: %v", err)
   402  	}
   403  }
   404  
   405  func expectUsageError(t *testing.T, err error) {
   406  	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != IncompatibleUsage {
   407  		t.Fatalf("error was not IncompatibleUsage: %v", err)
   408  	}
   409  }
   410  
   411  func expectAuthorityUnknown(t *testing.T, err error) {
   412  	e, ok := err.(UnknownAuthorityError)
   413  	if !ok {
   414  		t.Fatalf("error was not UnknownAuthorityError: %v", err)
   415  	}
   416  	if e.Cert == nil {
   417  		t.Fatalf("error was UnknownAuthorityError, but missing Cert: %v", err)
   418  	}
   419  }
   420  
   421  func expectHashError(t *testing.T, err error) {
   422  	if err == nil {
   423  		t.Fatalf("no error resulted from invalid hash")
   424  	}
   425  	if expected := "algorithm unimplemented"; !strings.Contains(err.Error(), expected) {
   426  		t.Fatalf("error resulting from invalid hash didn't contain '%s', rather it was: %v", expected, err)
   427  	}
   428  }
   429  
   430  func expectNameConstraintsError(t *testing.T, err error) {
   431  	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName {
   432  		t.Fatalf("error was not a CANotAuthorizedForThisName: %v", err)
   433  	}
   434  }
   435  
   436  func expectNotAuthorizedError(t *testing.T, err error) {
   437  	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign {
   438  		t.Fatalf("error was not a NotAuthorizedToSign: %v", err)
   439  	}
   440  }
   441  
   442  func expectUnhandledCriticalExtension(t *testing.T, err error) {
   443  	if _, ok := err.(UnhandledCriticalExtension); !ok {
   444  		t.Fatalf("error was not an UnhandledCriticalExtension: %v", err)
   445  	}
   446  }
   447  
   448  func certificateFromPEM(pemBytes string) (*Certificate, error) {
   449  	block, _ := pem.Decode([]byte(pemBytes))
   450  	if block == nil {
   451  		return nil, errors.New("failed to decode PEM")
   452  	}
   453  	return ParseCertificate(block.Bytes)
   454  }
   455  
   456  func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
   457  	opts := VerifyOptions{
   458  		Intermediates: NewCertPool(),
   459  		DNSName:       test.dnsName,
   460  		CurrentTime:   time.Unix(test.currentTime, 0),
   461  		KeyUsages:     test.keyUsages,
   462  	}
   463  
   464  	if !useSystemRoots {
   465  		opts.Roots = NewCertPool()
   466  		for j, root := range test.roots {
   467  			ok := opts.Roots.AppendCertsFromPEM([]byte(root))
   468  			if !ok {
   469  				t.Fatalf("failed to parse root #%d", j)
   470  			}
   471  		}
   472  	}
   473  
   474  	for j, intermediate := range test.intermediates {
   475  		ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
   476  		if !ok {
   477  			t.Fatalf("failed to parse intermediate #%d", j)
   478  		}
   479  	}
   480  
   481  	leaf, err := certificateFromPEM(test.leaf)
   482  	if err != nil {
   483  		t.Fatalf("failed to parse leaf: %v", err)
   484  	}
   485  
   486  	chains, err := leaf.Verify(opts)
   487  
   488  	if test.errorCallback == nil && err != nil {
   489  		if runtime.GOOS == "windows" && strings.HasSuffix(testenv.Builder(), "-2008") && err.Error() == "x509: certificate signed by unknown authority" {
   490  			testenv.SkipFlaky(t, 19564)
   491  		}
   492  		t.Fatalf("unexpected error: %v", err)
   493  	}
   494  	if test.errorCallback != nil {
   495  		if useSystemRoots && test.systemLax {
   496  			if err == nil {
   497  				t.Fatalf("expected error")
   498  			}
   499  		} else {
   500  			test.errorCallback(t, err)
   501  		}
   502  	}
   503  
   504  	doesMatch := func(expectedChain []string, chain []*Certificate) bool {
   505  		if len(chain) != len(expectedChain) {
   506  			return false
   507  		}
   508  
   509  		for k, cert := range chain {
   510  			if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
   511  				return false
   512  			}
   513  		}
   514  		return true
   515  	}
   516  
   517  	// Every expected chain should match one (or more) returned chain. We tolerate multiple
   518  	// matches, as due to root store semantics it is plausible that (at least on the system
   519  	// verifiers) multiple identical (looking) chains may be returned when two roots with the
   520  	// same subject are present.
   521  	for _, expectedChain := range test.expectedChains {
   522  		var match bool
   523  		for _, chain := range chains {
   524  			if doesMatch(expectedChain, chain) {
   525  				match = true
   526  				break
   527  			}
   528  		}
   529  
   530  		if !match {
   531  			t.Errorf("No match found for %v", expectedChain)
   532  		}
   533  	}
   534  
   535  	// Every returned chain should match 1 expected chain (or <2 if testing against the system)
   536  	for _, chain := range chains {
   537  		nMatched := 0
   538  		for _, expectedChain := range test.expectedChains {
   539  			if doesMatch(expectedChain, chain) {
   540  				nMatched++
   541  			}
   542  		}
   543  		// Allow additional unknown chains if systemLax is set
   544  		if nMatched == 0 && test.systemLax == false || nMatched > 1 {
   545  			t.Errorf("Got %v matches for chain %v", nMatched, chainToDebugString(chain))
   546  			for _, expectedChain := range test.expectedChains {
   547  				if doesMatch(expectedChain, chain) {
   548  					t.Errorf("\t matched %v", expectedChain)
   549  				}
   550  			}
   551  		}
   552  	}
   553  }
   554  
   555  func TestGoVerify(t *testing.T) {
   556  	// Temporarily enable SHA-1 verification since a number of test chains
   557  	// require it. TODO(filippo): regenerate test chains.
   558  	t.Setenv("GODEBUG", "x509sha1=1")
   559  
   560  	for _, test := range verifyTests {
   561  		t.Run(test.name, func(t *testing.T) {
   562  			testVerify(t, test, false)
   563  		})
   564  	}
   565  }
   566  
   567  func TestSystemVerify(t *testing.T) {
   568  	if runtime.GOOS != "windows" {
   569  		t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)
   570  	}
   571  
   572  	for _, test := range verifyTests {
   573  		t.Run(test.name, func(t *testing.T) {
   574  			if test.systemSkip {
   575  				t.SkipNow()
   576  			}
   577  			testVerify(t, test, true)
   578  		})
   579  	}
   580  }
   581  
   582  func chainToDebugString(chain []*Certificate) string {
   583  	var chainStr string
   584  	for _, cert := range chain {
   585  		if len(chainStr) > 0 {
   586  			chainStr += " -> "
   587  		}
   588  		chainStr += nameToKey(&cert.Subject)
   589  	}
   590  	return chainStr
   591  }
   592  
   593  func nameToKey(name *pkix.Name) string {
   594  	return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
   595  }
   596  
   597  const gtsIntermediate = `-----BEGIN CERTIFICATE-----
   598  MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
   599  CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
   600  MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
   601  MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
   602  Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
   603  ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
   604  kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
   605  lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
   606  BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
   607  gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
   608  tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
   609  DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
   610  AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
   611  VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
   612  CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
   613  AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
   614  MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
   615  A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
   616  aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
   617  AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
   618  cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
   619  RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
   620  +o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
   621  PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
   622  lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
   623  Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
   624  z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
   625  AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
   626  juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
   627  1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
   628  -----END CERTIFICATE-----`
   629  
   630  const gtsRoot = `-----BEGIN CERTIFICATE-----
   631  MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
   632  CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
   633  MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
   634  MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
   635  Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
   636  A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
   637  27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
   638  Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
   639  TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
   640  qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
   641  szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
   642  Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
   643  MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
   644  wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
   645  aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
   646  VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
   647  AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
   648  FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
   649  C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
   650  QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
   651  h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
   652  7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
   653  ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
   654  MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
   655  Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
   656  6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
   657  0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
   658  2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
   659  bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
   660  -----END CERTIFICATE-----`
   661  
   662  const googleLeaf = `-----BEGIN CERTIFICATE-----
   663  MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG
   664  MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
   665  QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
   666  ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
   667  AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
   668  wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
   669  55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
   670  N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
   671  KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
   672  WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
   673  DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
   674  MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
   675  f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
   676  aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
   677  cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
   678  b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
   679  VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
   680  TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
   681  4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
   682  3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
   683  1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
   684  hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
   685  IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF
   686  AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
   687  MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
   688  VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
   689  zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
   690  c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
   691  i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
   692  -----END CERTIFICATE-----`
   693  
   694  // googleLeafWithInvalidHash is the same as googleLeaf, but the signature
   695  // algorithm in the certificate contains a nonsense OID.
   696  const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
   697  MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG
   698  MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
   699  QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
   700  ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
   701  AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
   702  wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
   703  55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
   704  N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
   705  KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
   706  WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
   707  DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
   708  MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
   709  f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
   710  aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
   711  cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
   712  b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
   713  VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
   714  TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
   715  4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
   716  3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
   717  1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
   718  hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
   719  IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F
   720  AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
   721  MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
   722  VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
   723  zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
   724  c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
   725  i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
   726  -----END CERTIFICATE-----`
   727  
   728  const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
   729  MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
   730  TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
   731  YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
   732  MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTAwNzA0MTQ1MjQ1
   733  WhcNMTEwNzA1MTA1NzA0WjCBwTEgMB4GA1UEDRMXMjIxMTM3LWxpOWE5dHhJRzZM
   734  NnNyVFMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0
   735  ZWQxKTAnBgNVBAsTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMRsw
   736  GQYDVQQDExJ3d3cuZG5zc2VjLWV4cC5vcmcxKDAmBgkqhkiG9w0BCQEWGWhvc3Rt
   737  YXN0ZXJAZG5zc2VjLWV4cC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
   738  AoIBAQDEdF/22vaxrPbqpgVYMWi+alfpzBctpbfLBdPGuqOazJdCT0NbWcK8/+B4
   739  X6OlSOURNIlwLzhkmwVsWdVv6dVSaN7d4yI/fJkvgfDB9+au+iBJb6Pcz8ULBfe6
   740  D8HVvqKdORp6INzHz71z0sghxrQ0EAEkoWAZLh+kcn2ZHdcmZaBNUfjmGbyU6PRt
   741  RjdqoP+owIaC1aktBN7zl4uO7cRjlYFdusINrh2kPP02KAx2W84xjxX1uyj6oS6e
   742  7eBfvcwe8czW/N1rbE0CoR7h9+HnIrjnVG9RhBiZEiw3mUmF++Up26+4KTdRKbu3
   743  +BL4yMpfd66z0+zzqu+HkvyLpFn5AgMBAAGjggL/MIIC+zAJBgNVHRMEAjAAMAsG
   744  A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUy04I5guM
   745  drzfh2JQaXhgV86+4jUwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUw
   746  LQYDVR0RBCYwJIISd3d3LmRuc3NlYy1leHAub3Jngg5kbnNzZWMtZXhwLm9yZzCC
   747  AUIGA1UdIASCATkwggE1MIIBMQYLKwYBBAGBtTcBAgIwggEgMC4GCCsGAQUFBwIB
   748  FiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIB
   749  FihodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMIG3Bggr
   750  BgEFBQcCAjCBqjAUFg1TdGFydENvbSBMdGQuMAMCAQEagZFMaW1pdGVkIExpYWJp
   751  bGl0eSwgc2VlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRpb25zKiBvZiB0aGUgU3Rh
   752  cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9saWN5IGF2YWlsYWJsZSBh
   753  dCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMGEGA1UdHwRaMFgw
   754  KqAooCaGJGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2NydDEtY3JsLmNybDAqoCig
   755  JoYkaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMIGOBggrBgEF
   756  BQcBAQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20v
   757  c3ViL2NsYXNzMS9zZXJ2ZXIvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuc3Rh
   758  cnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuc2VydmVyLmNhLmNydDAjBgNVHRIE
   759  HDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEB
   760  ACXj6SB59KRJPenn6gUdGEqcta97U769SATyiQ87i9er64qLwvIGLMa3o2Rcgl2Y
   761  kghUeyLdN/EXyFBYA8L8uvZREPoc7EZukpT/ZDLXy9i2S0jkOxvF2fD/XLbcjGjM
   762  iEYG1/6ASw0ri9C0k4oDDoJLCoeH9++yqF7SFCCMcDkJqiAGXNb4euDpa8vCCtEQ
   763  CSS+ObZbfkreRt3cNCf5LfCXe9OsTnCfc8Cuq81c0oLaG+SmaLUQNBuToq8e9/Zm
   764  +b+/a3RVjxmkV5OCcGVBxsXNDn54Q6wsdw0TBMcjwoEndzpLS7yWgFbbkq5ZiGpw
   765  Qibb2+CfKuQ+WFV1GkVQmVA=
   766  -----END CERTIFICATE-----`
   767  
   768  const startComIntermediate = `-----BEGIN CERTIFICATE-----
   769  MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
   770  MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
   771  Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
   772  dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB
   773  jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
   774  IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
   775  YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
   776  IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE
   777  gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA
   778  pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv
   779  kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/
   780  ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5
   781  xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID
   782  AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
   783  VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul
   784  F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
   785  L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
   786  YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
   787  dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
   788  c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
   789  BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
   790  BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
   791  LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp
   792  tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen
   793  xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw
   794  xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X
   795  t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI
   796  RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi
   797  YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L
   798  WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN
   799  SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD
   800  wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L
   801  p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un
   802  0q6Dp6jOW6c=
   803  -----END CERTIFICATE-----`
   804  
   805  const startComRoot = `-----BEGIN CERTIFICATE-----
   806  MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
   807  MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
   808  Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
   809  dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
   810  MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
   811  U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
   812  cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
   813  A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
   814  pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
   815  OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
   816  Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
   817  Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
   818  HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
   819  Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
   820  +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
   821  Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
   822  Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
   823  26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
   824  AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
   825  FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
   826  ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
   827  LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
   828  BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
   829  Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
   830  dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
   831  cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
   832  YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
   833  dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
   834  bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
   835  YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
   836  TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
   837  9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
   838  jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
   839  FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
   840  ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
   841  ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
   842  EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
   843  L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
   844  yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
   845  O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
   846  um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
   847  NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
   848  -----END CERTIFICATE-----`
   849  
   850  const smimeLeaf = `-----BEGIN CERTIFICATE-----
   851  MIIIPDCCBiSgAwIBAgIQaMDxFS0pOMxZZeOBxoTJtjANBgkqhkiG9w0BAQsFADCB
   852  nTELMAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMTowOAYDVQQLDDFB
   853  WlogWml1cnRhZ2lyaSBwdWJsaWtvYSAtIENlcnRpZmljYWRvIHB1YmxpY28gU0NB
   854  MTwwOgYDVQQDDDNFQUVrbyBIZXJyaSBBZG1pbmlzdHJhemlvZW4gQ0EgLSBDQSBB
   855  QVBQIFZhc2NhcyAoMikwHhcNMTcwNzEyMDg1MzIxWhcNMjEwNzEyMDg1MzIxWjCC
   856  AQwxDzANBgNVBAoMBklaRU5QRTE4MDYGA1UECwwvWml1cnRhZ2lyaSBrb3Jwb3Jh
   857  dGlib2EtQ2VydGlmaWNhZG8gY29ycG9yYXRpdm8xQzBBBgNVBAsMOkNvbmRpY2lv
   858  bmVzIGRlIHVzbyBlbiB3d3cuaXplbnBlLmNvbSBub2xhIGVyYWJpbGkgamFraXRl
   859  a28xFzAVBgNVBC4TDi1kbmkgOTk5OTk5ODlaMSQwIgYDVQQDDBtDT1JQT1JBVElW
   860  TyBGSUNUSUNJTyBBQ1RJVk8xFDASBgNVBCoMC0NPUlBPUkFUSVZPMREwDwYDVQQE
   861  DAhGSUNUSUNJTzESMBAGA1UEBRMJOTk5OTk5ODlaMIIBIjANBgkqhkiG9w0BAQEF
   862  AAOCAQ8AMIIBCgKCAQEAwVOMwUDfBtsH0XuxYnb+v/L774jMH8valX7RPH8cl2Lb
   863  SiqSo0RchW2RGA2d1yuYHlpChC9jGmt0X/g66/E/+q2hUJlfJtqVDJFwtFYV4u2S
   864  yzA3J36V4PRkPQrKxAsbzZriFXAF10XgiHQz9aVeMMJ9GBhmh9+DK8Tm4cMF6i8l
   865  +AuC35KdngPF1x0ealTYrYZplpEJFO7CiW42aLi6vQkDR2R7nmZA4AT69teqBWsK
   866  0DZ93/f0G/3+vnWwNTBF0lB6dIXoaz8OMSyHLqGnmmAtMrzbjAr/O/WWgbB/BqhR
   867  qjJQ7Ui16cuDldXaWQ/rkMzsxmsAox0UF+zdQNvXUQIDAQABo4IDBDCCAwAwgccG
   868  A1UdEgSBvzCBvIYVaHR0cDovL3d3dy5pemVucGUuY29tgQ9pbmZvQGl6ZW5wZS5j
   869  b22kgZEwgY4xRzBFBgNVBAoMPklaRU5QRSBTLkEuIC0gQ0lGIEEwMTMzNzI2MC1S
   870  TWVyYy5WaXRvcmlhLUdhc3RlaXogVDEwNTUgRjYyIFM4MUMwQQYDVQQJDDpBdmRh
   871  IGRlbCBNZWRpdGVycmFuZW8gRXRvcmJpZGVhIDE0IC0gMDEwMTAgVml0b3JpYS1H
   872  YXN0ZWl6MB4GA1UdEQQXMBWBE2ZpY3RpY2lvQGl6ZW5wZS5ldXMwDgYDVR0PAQH/
   873  BAQDAgXgMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQC
   874  AjAdBgNVHQ4EFgQUyeoOD4cgcljKY0JvrNuX2waFQLAwHwYDVR0jBBgwFoAUwKlK
   875  90clh/+8taaJzoLSRqiJ66MwggEnBgNVHSAEggEeMIIBGjCCARYGCisGAQQB8zkB
   876  AQEwggEGMDMGCCsGAQUFBwIBFidodHRwOi8vd3d3Lml6ZW5wZS5jb20vcnBhc2Nh
   877  Y29ycG9yYXRpdm8wgc4GCCsGAQUFBwICMIHBGoG+Wml1cnRhZ2lyaWEgRXVza2Fs
   878  IEF1dG9ub21pYSBFcmtpZGVnb2tvIHNla3RvcmUgcHVibGlrb2tvIGVyYWt1bmRl
   879  ZW4gYmFybmUtc2FyZWV0YW4gYmFrYXJyaWsgZXJhYmlsIGRhaXRla2UuIFVzbyBy
   880  ZXN0cmluZ2lkbyBhbCBhbWJpdG8gZGUgcmVkZXMgaW50ZXJuYXMgZGUgRW50aWRh
   881  ZGVzIGRlbCBTZWN0b3IgUHVibGljbyBWYXNjbzAyBggrBgEFBQcBAQQmMCQwIgYI
   882  KwYBBQUHMAGGFmh0dHA6Ly9vY3NwLml6ZW5wZS5jb20wOgYDVR0fBDMwMTAvoC2g
   883  K4YpaHR0cDovL2NybC5pemVucGUuY29tL2NnaS1iaW4vY3JsaW50ZXJuYTIwDQYJ
   884  KoZIhvcNAQELBQADggIBAIy5PQ+UZlCRq6ig43vpHwlwuD9daAYeejV0Q+ZbgWAE
   885  GtO0kT/ytw95ZEJMNiMw3fYfPRlh27ThqiT0VDXZJDlzmn7JZd6QFcdXkCsiuv4+
   886  ZoXAg/QwnA3SGUUO9aVaXyuOIIuvOfb9MzoGp9xk23SMV3eiLAaLMLqwB5DTfBdt
   887  BGI7L1MnGJBv8RfP/TL67aJ5bgq2ri4S8vGHtXSjcZ0+rCEOLJtmDNMnTZxancg3
   888  /H5edeNd+n6Z48LO+JHRxQufbC4mVNxVLMIP9EkGUejlq4E4w6zb5NwCQczJbSWL
   889  i31rk2orsNsDlyaLGsWZp3JSNX6RmodU4KAUPor4jUJuUhrrm3Spb73gKlV/gcIw
   890  bCE7mML1Kss3x1ySaXsis6SZtLpGWKkW2iguPWPs0ydV6RPhmsCxieMwPPIJ87vS
   891  5IejfgyBae7RSuAIHyNFy4uI5xwvwUFf6OZ7az8qtW7ImFOgng3Ds+W9k1S2CNTx
   892  d0cnKTfA6IpjGo8EeHcxnIXT8NPImWaRj0qqonvYady7ci6U4m3lkNSdXNn1afgw
   893  mYust+gxVtOZs1gk2MUCgJ1V1X+g7r/Cg7viIn6TLkLrpS1kS1hvMqkl9M+7XqPo
   894  Qd95nJKOkusQpy99X4dF/lfbYAQnnjnqh3DLD2gvYObXFaAYFaiBKTiMTV2X72F+
   895  -----END CERTIFICATE-----`
   896  
   897  const smimeIntermediate = `-----BEGIN CERTIFICATE-----
   898  MIIHNzCCBSGgAwIBAgIQJMXIqlZvjuhMvqcFXOFkpDALBgkqhkiG9w0BAQswODEL
   899  MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu
   900  cGUuY29tMB4XDTEwMTAyMDA4MjMzM1oXDTM3MTIxMjIzMDAwMFowgZ0xCzAJBgNV
   901  BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0
   902  YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UE
   903  AwwzRUFFa28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNj
   904  YXMgKDIpMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoIM7nEdI0N1h
   905  rR5T4xuV/usKDoMIasaiKvfLhbwxaNtTt+a7W/6wV5bv3svQFIy3sUXjjdzV1nG2
   906  To2wo/YSPQiOt8exWvOapvL21ogiof+kelWnXFjWaKJI/vThHYLgIYEMj/y4HdtU
   907  ojI646rZwqsb4YGAopwgmkDfUh5jOhV2IcYE3TgJAYWVkj6jku9PLaIsHiarAHjD
   908  PY8dig8a4SRv0gm5Yk7FXLmW1d14oxQBDeHZ7zOEXfpafxdEDO2SNaRJjpkh8XRr
   909  PGqkg2y1Q3gT6b4537jz+StyDIJ3omylmlJsGCwqT7p8mEqjGJ5kC5I2VnjXKuNn
   910  soShc72khWZVUJiJo5SGuAkNE2ZXqltBVm5Jv6QweQKsX6bkcMc4IZok4a+hx8FM
   911  8IBpGf/I94pU6HzGXqCyc1d46drJgDY9mXa+6YDAJFl3xeXOOW2iGCfwXqhiCrKL
   912  MYvyMZzqF3QH5q4nb3ZnehYvraeMFXJXDn+Utqp8vd2r7ShfQJz01KtM4hgKdgSg
   913  jtW+shkVVN5ng/fPN85ovfAH2BHXFfHmQn4zKsYnLitpwYM/7S1HxlT61cdQ7Nnk
   914  3LZTYEgAoOmEmdheklT40WAYakksXGM5VrzG7x9S7s1Tm+Vb5LSThdHC8bxxwyTb
   915  KsDRDNJ84N9fPDO6qHnzaL2upQ43PycCAwEAAaOCAdkwggHVMIHHBgNVHREEgb8w
   916  gbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5mb0BpemVucGUuY29tpIGRMIGO
   917  MUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBBMDEzMzcyNjAtUk1lcmMuVml0
   918  b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEGA1UECQw6QXZkYSBkZWwgTWVk
   919  aXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEwIFZpdG9yaWEtR2FzdGVpejAP
   920  BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUwKlK90cl
   921  h/+8taaJzoLSRqiJ66MwHwYDVR0jBBgwFoAUHRxlDqjyJXu0kc/ksbHmvVV0bAUw
   922  OgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHA6Ly93d3cuaXpl
   923  bnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v
   924  b2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny
   925  bC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjALBgkqhkiG9w0BAQsDggIBAMbjc3HM
   926  3DG9ubWPkzsF0QsktukpujbTTcGk4h20G7SPRy1DiiTxrRzdAMWGjZioOP3/fKCS
   927  M539qH0M+gsySNie+iKlbSZJUyE635T1tKw+G7bDUapjlH1xyv55NC5I6wCXGC6E
   928  3TEP5B/E7dZD0s9E4lS511ubVZivFgOzMYo1DO96diny/N/V1enaTCpRl1qH1OyL
   929  xUYTijV4ph2gL6exwuG7pxfRcVNHYlrRaXWfTz3F6NBKyULxrI3P/y6JAtN1GqT4
   930  VF/+vMygx22n0DufGepBwTQz6/rr1ulSZ+eMnuJiTXgh/BzQnkUsXTb8mHII25iR
   931  0oYF2qAsk6ecWbLiDpkHKIDHmML21MZE13MS8NSvTHoqJO4LyAmDe6SaeNHtrPlK
   932  b6mzE1BN2ug+ZaX8wLA5IMPFaf0jKhb/Cxu8INsxjt00brsErCc9ip1VNaH0M4bi
   933  1tGxfiew2436FaeyUxW7Pl6G5GgkNbuUc7QIoRy06DdU/U38BxW3uyJMY60zwHvS
   934  FlKAn0OvYp4niKhAJwaBVN3kowmJuOU5Rid+TUnfyxbJ9cttSgzaF3hP/N4zgMEM
   935  5tikXUskeckt8LUK96EH0QyssavAMECUEb/xrupyRdYWwjQGvNLq6T5+fViDGyOw
   936  k+lzD44wofy8paAy9uC9Owae0zMEzhcsyRm7
   937  -----END CERTIFICATE-----`
   938  
   939  const smimeRoot = `-----BEGIN CERTIFICATE-----
   940  MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
   941  MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
   942  ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
   943  VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
   944  b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
   945  scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
   946  xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
   947  LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
   948  uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
   949  yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
   950  JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
   951  rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
   952  BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
   953  hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
   954  QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
   955  HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
   956  Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
   957  QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
   958  BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
   959  MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
   960  AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
   961  A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
   962  laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
   963  awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
   964  JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
   965  LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
   966  VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
   967  LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
   968  UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
   969  QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
   970  naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
   971  QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
   972  -----END CERTIFICATE-----`
   973  
   974  var nameConstraintsLeaf = `-----BEGIN CERTIFICATE-----
   975  MIIHMTCCBRmgAwIBAgIIIZaV/3ezOJkwDQYJKoZIhvcNAQEFBQAwgcsxCzAJBgNV
   976  BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEj
   977  MCEGA1UECxMaR2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1Zp
   978  cmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0
   979  eTExMC8GA1UEAxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZl
   980  ciBDQTAeFw0xMzA5MTkxNDM2NTVaFw0xNTA5MTkxNDM2NTVaMIHNMQswCQYDVQQG
   981  EwJVUzERMA8GA1UECAwIVmlyZ2luaWExEzARBgNVBAcMCkJsYWNrc2J1cmcxPDA6
   982  BgNVBAoMM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUg
   983  VW5pdmVyc2l0eTE7MDkGA1UECwwyVGVjaG5vbG9neS1lbmhhbmNlZCBMZWFybmlu
   984  ZyBhbmQgT25saW5lIFN0cmF0ZWdpZXMxGzAZBgNVBAMMEnNlY3VyZS5pZGRsLnZ0
   985  LmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkOyPpsOK/6IuPG
   986  WnIBlVwlHzeYf+cUlggqkLq0b0+vZbiTXgio9/VCuNQ8opSoss7J7o3ygV9to+9Y
   987  YwJKVC5WDT/y5JWpQey0CWILymViJnpNSwnxBc8A+Q8w5NUGDd/UhtPx/U8/hqbd
   988  WPDYj2hbOqyq8UlRhfS5pwtnv6BbCTaY11I6FhCLK7zttISyTuWCf9p9o/ggiipP
   989  ii/5oh4dkl+r5SfuSp5GPNHlYO8lWqys5NAPoDD4fc/kuflcK7Exx7XJ+Oqu0W0/
   990  psjEY/tES1ZgDWU/ParcxxFpFmKHbD5DXsfPOObzkVWXIY6tGMutSlE1Froy/Nn0
   991  OZsAOrcCAwEAAaOCAhMwggIPMIG4BggrBgEFBQcBAQSBqzCBqDBYBggrBgEFBQcw
   992  AoZMaHR0cDovL3d3dy5wa2kudnQuZWR1L2dsb2JhbHF1YWxpZmllZHNlcnZlci9j
   993  YWNlcnQvZ2xvYmFscXVhbGlmaWVkc2VydmVyLmNydDBMBggrBgEFBQcwAYZAaHR0
   994  cDovL3Z0Y2EtcC5lcHJvdi5zZXRpLnZ0LmVkdTo4MDgwL2VqYmNhL3B1YmxpY3dl
   995  Yi9zdGF0dXMvb2NzcDAdBgNVHQ4EFgQUp7xbO6iHkvtZbPE4jmndmnAbSEcwDAYD
   996  VR0TAQH/BAIwADAfBgNVHSMEGDAWgBS8YmAn1eM1SBfpS6tFatDIqHdxjDBqBgNV
   997  HSAEYzBhMA4GDCsGAQQBtGgFAgICATAOBgwrBgEEAbRoBQICAQEwPwYMKwYBBAG0
   998  aAUCAgMBMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9i
   999  YWwvY3BzLzBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vd3d3LnBraS52dC5lZHUv
  1000  Z2xvYmFscXVhbGlmaWVkc2VydmVyL2NybC9jYWNybC5jcmwwDgYDVR0PAQH/BAQD
  1001  AgTwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHREEFjAUghJz
  1002  ZWN1cmUuaWRkbC52dC5lZHUwDQYJKoZIhvcNAQEFBQADggIBAEgoYo4aUtatY3gI
  1003  OyyKp7QlIOaLbTJZywESHqy+L5EGDdJW2DJV+mcE0LDGvqa2/1Lo+AR1ntsZwfOi
  1004  Y718JwgVVaX/RCd5+QKP25c5/x72xI8hb/L1bgS0ED9b0YAhd7Qm1K1ot82+6mqX
  1005  DW6WiGeDr8Z07MQ3143qQe2rBlq+QI69DYzm2GOqAIAnUIWv7tCyLUm31b4DwmrJ
  1006  TeudVreTKUbBNB1TWRFHEPkWhjjXKZnNGRO11wHXcyBu6YekIvVZ+vmx8ePee4jJ
  1007  3GFOi7lMuWOeq57jTVL7KOKaKLVXBb6gqo5aq+Wwt8RUD5MakrCAEeQZj7DKaFmZ
  1008  oQCO0Pxrsl3InCGvxnGzT+bFVO9nJ/BAMj7hknFdm9Jr6Bg5q33Z+gnf909AD9QF
  1009  ESqUSykaHu2LVdJx2MaCH1CyKnRgMw5tEwE15EXpUjCm24m8FMOYC+rNtf18pgrz
  1010  5D8Jhh+oxK9PjcBYqXNtnioIxiMCYcV0q5d4w4BYFEh71tk7/bYB0R55CsBUVPmp
  1011  timWNOdRd57Tfpk3USaVsumWZAf9MP3wPiC7gb4d5tYEEAG5BuDT8ruFw838wU8G
  1012  1VvAVutSiYBg7k3NYO7AUqZ+Ax4klQX3aM9lgonmJ78Qt94UPtbptrfZ4/lSqEf8
  1013  GBUwDrQNTb+gsXsDkjd5lcYxNx6l
  1014  -----END CERTIFICATE-----`
  1015  
  1016  var nameConstraintsIntermediate1 = `-----BEGIN CERTIFICATE-----
  1017  MIINLjCCDBagAwIBAgIRIqpyf/YoGgvHc8HiDAxAI8owDQYJKoZIhvcNAQEFBQAw
  1018  XDELMAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQ
  1019  R2xvYmFsU2lnbiBudi1zYTEbMBkGA1UEAxMSVHJ1c3RlZCBSb290IENBIEcyMB4X
  1020  DTEyMTIxMzAwMDAwMFoXDTE3MTIxMzAwMDAwMFowgcsxCzAJBgNVBAYTAlVTMREw
  1021  DwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEjMCEGA1UECxMa
  1022  R2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1ZpcmdpbmlhIFBv
  1023  bHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTExMC8GA1UE
  1024  AxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZlciBDQTCCAiIw
  1025  DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALgIZhEaptBWADBqdJ45ueFGzMXa
  1026  GHnzNxoxR1fQIaaRQNdCg4cw3A4dWKMeEgYLtsp65ai3Xfw62Qaus0+KJ3RhgV+r
  1027  ihqK81NUzkls78fJlADVDI4fCTlothsrE1CTOMiy97jKHai5mVTiWxmcxpmjv7fm
  1028  5Nhc+uHgh2hIz6npryq495mD51ZrUTIaqAQN6Pw/VHfAmR524vgriTOjtp1t4lA9
  1029  pXGWjF/vkhAKFFheOQSQ00rngo2wHgCqMla64UTN0oz70AsCYNZ3jDLx0kOP0YmM
  1030  R3Ih91VA63kLqPXA0R6yxmmhhxLZ5bcyAy1SLjr1N302MIxLM/pSy6aquEnbELhz
  1031  qyp9yGgRyGJay96QH7c4RJY6gtcoPDbldDcHI9nXngdAL4DrZkJ9OkDkJLyqG66W
  1032  ZTF5q4EIs6yMdrywz0x7QP+OXPJrjYpbeFs6tGZCFnWPFfmHCRJF8/unofYrheq+
  1033  9J7Jx3U55S/k57NXbAM1RAJOuMTlfn9Etf9Dpoac9poI4Liav6rBoUQk3N3JWqnV
  1034  HNx/NdCyJ1/6UbKMJUZsStAVglsi6lVPo289HHOE4f7iwl3SyekizVOp01wUin3y
  1035  cnbZB/rXmZbwapSxTTSBf0EIOr9i4EGfnnhCAVA9U5uLrI5OEB69IY8PNX0071s3
  1036  Z2a2fio5c8m3JkdrAgMBAAGjggh5MIIIdTAOBgNVHQ8BAf8EBAMCAQYwTAYDVR0g
  1037  BEUwQzBBBgkrBgEEAaAyATwwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
  1038  YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wEgYDVR0TAQH/BAgwBgEB/wIBADCCBtAG
  1039  A1UdHgSCBscwggbDoIIGvzASghAzZGJsYWNrc2J1cmcub3JnMBiCFmFjY2VsZXJh
  1040  dGV2aXJnaW5pYS5jb20wGIIWYWNjZWxlcmF0ZXZpcmdpbmlhLm9yZzALgglhY3Zj
  1041  cC5vcmcwCYIHYmV2Lm5ldDAJggdiZXYub3JnMAuCCWNsaWdzLm9yZzAMggpjbWl3
  1042  ZWIub3JnMBeCFWVhc3Rlcm5icm9va3Ryb3V0Lm5ldDAXghVlYXN0ZXJuYnJvb2t0
  1043  cm91dC5vcmcwEYIPZWNvcnJpZG9ycy5pbmZvMBOCEWVkZ2FycmVzZWFyY2gub3Jn
  1044  MBKCEGdldC1lZHVjYXRlZC5jb20wE4IRZ2V0LWVkdWNhdGVkLmluZm8wEYIPZ2V0
  1045  ZWR1Y2F0ZWQubmV0MBKCEGdldC1lZHVjYXRlZC5uZXQwEYIPZ2V0ZWR1Y2F0ZWQu
  1046  b3JnMBKCEGdldC1lZHVjYXRlZC5vcmcwD4INaG9raWVjbHViLmNvbTAQgg5ob2tp
  1047  ZXBob3RvLmNvbTAPgg1ob2tpZXNob3AuY29tMBGCD2hva2llc3BvcnRzLmNvbTAS
  1048  ghBob2tpZXRpY2tldHMuY29tMBKCEGhvdGVscm9hbm9rZS5jb20wE4IRaHVtYW53
  1049  aWxkbGlmZS5vcmcwF4IVaW5uYXR2aXJnaW5pYXRlY2guY29tMA+CDWlzY2hwMjAx
  1050  MS5vcmcwD4INbGFuZHJlaGFiLm9yZzAggh5uYXRpb25hbHRpcmVyZXNlYXJjaGNl
  1051  bnRlci5jb20wFYITbmV0d29ya3ZpcmdpbmlhLm5ldDAMggpwZHJjdnQuY29tMBiC
  1052  FnBldGVkeWVyaXZlcmNvdXJzZS5jb20wDYILcmFkaW9pcS5vcmcwFYITcml2ZXJj
  1053  b3Vyc2Vnb2xmLmNvbTALgglzZGltaS5vcmcwEIIOc292YW1vdGlvbi5jb20wHoIc
  1054  c3VzdGFpbmFibGUtYmlvbWF0ZXJpYWxzLmNvbTAeghxzdXN0YWluYWJsZS1iaW9t
  1055  YXRlcmlhbHMub3JnMBWCE3RoaXNpc3RoZWZ1dHVyZS5jb20wGIIWdGhpcy1pcy10
  1056  aGUtZnV0dXJlLmNvbTAVghN0aGlzaXN0aGVmdXR1cmUubmV0MBiCFnRoaXMtaXMt
  1057  dGhlLWZ1dHVyZS5uZXQwCoIIdmFkcy5vcmcwDIIKdmFsZWFmLm9yZzANggt2YXRl
  1058  Y2guaW5mbzANggt2YXRlY2gubW9iaTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5n
  1059  LmNvbTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5nLm5ldDAcghp2YXRlY2hsaWZl
  1060  bG9uZ2xlYXJuaW5nLm9yZzAKggh2Y29tLmVkdTASghB2aXJnaW5pYXZpZXcubmV0
  1061  MDSCMnZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVuaXZlcnNp
  1062  dHkuY29tMDWCM3ZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVu
  1063  aXZlcnNpdHkuaW5mbzA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0dXRlYW5k
  1064  c3RhdGV1bml2ZXJzaXR5Lm5ldDA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0
  1065  dXRlYW5kc3RhdGV1bml2ZXJzaXR5Lm9yZzAZghd2aXJnaW5pYXB1YmxpY3JhZGlv
  1066  Lm9yZzASghB2aXJnaW5pYXRlY2guZWR1MBOCEXZpcmdpbmlhdGVjaC5tb2JpMByC
  1067  GnZpcmdpbmlhdGVjaGZvdW5kYXRpb24ub3JnMAiCBnZ0LmVkdTALggl2dGFyYy5v
  1068  cmcwDIIKdnQtYXJjLm9yZzALggl2dGNyYy5jb20wCoIIdnRpcC5vcmcwDIIKdnRs
  1069  ZWFuLm9yZzAWghR2dGtub3dsZWRnZXdvcmtzLmNvbTAYghZ2dGxpZmVsb25nbGVh
  1070  cm5pbmcuY29tMBiCFnZ0bGlmZWxvbmdsZWFybmluZy5uZXQwGIIWdnRsaWZlbG9u
  1071  Z2xlYXJuaW5nLm9yZzATghF2dHNwb3J0c21lZGlhLmNvbTALggl2dHdlaS5jb20w
  1072  D4INd2l3YXR3ZXJjLmNvbTAKggh3dnRmLm9yZzAIgQZ2dC5lZHUwd6R1MHMxCzAJ
  1073  BgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVy
  1074  ZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBT
  1075  dGF0ZSBVbml2ZXJzaXR5MCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYI
  1076  KwYBBQUHAwkwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5nbG9iYWxzaWdu
  1077  LmNvbS9ncy90cnVzdHJvb3RnMi5jcmwwgYQGCCsGAQUFBwEBBHgwdjAzBggrBgEF
  1078  BQcwAYYnaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3RydXN0cm9vdGcyMD8G
  1079  CCsGAQUFBzAChjNodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90
  1080  cnVzdHJvb3RnMi5jcnQwHQYDVR0OBBYEFLxiYCfV4zVIF+lLq0Vq0Miod3GMMB8G
  1081  A1UdIwQYMBaAFBT25YsxtkWASkxt/MKHico2w5BiMA0GCSqGSIb3DQEBBQUAA4IB
  1082  AQAyJm/lOB2Er4tHXhc/+fSufSzgjohJgYfMkvG4LknkvnZ1BjliefR8tTXX49d2
  1083  SCDFWfGjqyJZwavavkl/4p3oXPG/nAMDMvxh4YAT+CfEK9HH+6ICV087kD4BLegi
  1084  +aFJMj8MMdReWCzn5sLnSR1rdse2mo2arX3Uod14SW+PGrbUmTuWNyvRbz3fVmxp
  1085  UdbGmj3laknO9YPsBGgHfv73pVVsTJkW4ZfY/7KdD/yaVv6ophpOB3coXfjl2+kd
  1086  Z4ypn2zK+cx9IL/LSewqd/7W9cD55PCUy4X9OTbEmAccwiz3LB66mQoUGfdHdkoB
  1087  jUY+v9vLQXmaVwI0AYL7g9LN
  1088  -----END CERTIFICATE-----`
  1089  
  1090  var nameConstraintsIntermediate2 = `-----BEGIN CERTIFICATE-----
  1091  MIIEXTCCA0WgAwIBAgILBAAAAAABNuk6OrMwDQYJKoZIhvcNAQEFBQAwVzELMAkG
  1092  A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
  1093  b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMjA0MjUxMTAw
  1094  MDBaFw0yNzA0MjUxMTAwMDBaMFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVz
  1095  dGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRy
  1096  dXN0ZWQgUm9vdCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
  1097  AKyuvqrtcMr7g7EuNbu4sKwxM127UsCmx1RxbxxgcArGS7rjiefpBH/w4LYrymjf
  1098  vcw1ueyMNoqLo9nJMz/ORXupb35NNfE667prQYHa+tTjl1IiKpB7QUwt3wXPuTMF
  1099  Ja1tXtjKzkqJyuJlNuPKT76HcjgNqgV1s9qG44MD5I2JvI12du8zI1bgdQ+l/KsX
  1100  kTfbGjUvhOLOlVNWVQDpL+YMIrGqgBYxy5TUNgrAcRtwpNdS2KkF5otSmMweVb5k
  1101  hoUVv3u8UxQH/WWbNhHq1RrIlg/0rBUfi/ziShYFSB7U+aLx5DxPphTFBiDquQGp
  1102  tB+FC4JvnukDStFihZCZ1R8CAwEAAaOCASMwggEfMA4GA1UdDwEB/wQEAwIBBjAP
  1103  BgNVHRMBAf8EBTADAQH/MEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB
  1104  FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAdBgNVHQ4E
  1105  FgQUFPblizG2RYBKTG38woeJyjbDkGIwMwYDVR0fBCwwKjAooCagJIYiaHR0cDov
  1106  L2NybC5nbG9iYWxzaWduLm5ldC9yb290LmNybDA+BggrBgEFBQcBAQQyMDAwLgYI
  1107  KwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjEwHwYD
  1108  VR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEFBQADggEB
  1109  AL7IG0l+k4LkcpI+a/kvZsSRwSM4uA6zGX34e78A2oytr8RG8bJwVb8+AHMUD+Xe
  1110  2kYdh/Uj/waQXfqR0OgxQXL9Ct4ZM+JlR1avsNKXWL5AwYXAXCOB3J5PW2XOck7H
  1111  Zw0vRbGQhjWjQx+B4KOUFg1b3ov/z6Xkr3yaCfRQhXh7KC0Bc0RXPPG5Nv5lCW+z
  1112  tbbg0zMm3kyfQITRusMSg6IBsDJqOnjaiaKQRcXiD0Sk43ZXb2bUKMxC7+Td3QL4
  1113  RyHcWJbQ7YylLTS/x+jxWIcOQ0oO5/54t5PTQ14neYhOz9x4gUk2AYAW6d1vePwb
  1114  hcC8roQwkHT7HvfYBoc74FM=
  1115  -----END CERTIFICATE-----`
  1116  
  1117  var globalSignRoot = `-----BEGIN CERTIFICATE-----
  1118  MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
  1119  A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
  1120  b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
  1121  MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
  1122  YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
  1123  aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
  1124  jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
  1125  xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
  1126  1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
  1127  snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
  1128  U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
  1129  9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
  1130  BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
  1131  AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
  1132  yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
  1133  38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
  1134  AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
  1135  DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
  1136  HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
  1137  -----END CERTIFICATE-----`
  1138  
  1139  const digicertRoot = `-----BEGIN CERTIFICATE-----
  1140  MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
  1141  MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
  1142  d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
  1143  QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
  1144  MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
  1145  b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
  1146  9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
  1147  CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
  1148  nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
  1149  43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
  1150  T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
  1151  gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
  1152  BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
  1153  TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
  1154  DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
  1155  hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
  1156  06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
  1157  PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
  1158  YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
  1159  CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
  1160  -----END CERTIFICATE-----`
  1161  
  1162  const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE-----
  1163  MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh
  1164  MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
  1165  d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
  1166  QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO
  1167  MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD
  1168  ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
  1169  IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR
  1170  xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v
  1171  Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD
  1172  VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G
  1173  A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA
  1174  MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl
  1175  cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt
  1176  Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG
  1177  SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v
  1178  Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd
  1179  j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV
  1180  OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk
  1181  GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa
  1182  SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq
  1183  PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6
  1184  rRzZxAYN36q1SX8=
  1185  -----END CERTIFICATE-----`
  1186  
  1187  const trustAsiaLeaf = `-----BEGIN CERTIFICATE-----
  1188  MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw
  1189  CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j
  1190  LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx
  1191  NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI
  1192  DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo
  1193  5Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm
  1194  nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
  1195  AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL
  1196  TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/
  1197  +LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud
  1198  EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
  1199  BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny
  1200  bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD
  1201  VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu
  1202  ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG
  1203  AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG
  1204  OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM
  1205  U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv
  1206  AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA
  1207  RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8
  1208  leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K
  1209  tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx
  1210  x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw
  1211  CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z
  1212  0GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364
  1213  EEeHB9vhZAEjQSePAfjR9aAGhXRa
  1214  -----END CERTIFICATE-----`
  1215  
  1216  const selfSigned = `-----BEGIN CERTIFICATE-----
  1217  MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw
  1218  EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz
  1219  NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
  1220  ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP
  1221  pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF
  1222  w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D
  1223  WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY
  1224  YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO
  1225  NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF
  1226  oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C
  1227  C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim
  1228  4EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN
  1229  UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0
  1230  pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG
  1231  vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
  1232  cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
  1233  -----END CERTIFICATE-----`
  1234  
  1235  const issuerSubjectMatchRoot = `-----BEGIN CERTIFICATE-----
  1236  MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
  1237  ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1
  1238  MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh
  1239  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
  1240  siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
  1241  +QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
  1242  JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
  1243  FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
  1244  EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAb4TfSeCZ1HFmHTKG
  1245  VsvqWmsOAGrRWm4fBiMH/8vRGnTkJEMLqiqgc3Ulgry/P6n4SIis7TqUOw3TiMhn
  1246  RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3
  1247  eyfm5ITdK/WT9TzYhsU4AVZcn20=
  1248  -----END CERTIFICATE-----`
  1249  
  1250  const issuerSubjectMatchLeaf = `-----BEGIN CERTIFICATE-----
  1251  MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV
  1252  BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y
  1253  NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB
  1254  nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA20Z9ky4SJwZIvAYoIat+xLaiXf4e
  1255  UkWIejZHpQgNkkJbwoHAvpd5mED7T20U/SsTi8KlLmfY1Ame1iI4t0oLdHMrwjTx
  1256  0ZPlltl0e/NYn2xhPMCwQdTZKyskI3dbHDu9dV3OIFTPoWOHHR4kxPMdGlCLqrYU
  1257  Q+2Xp3Vi9BTIUtcCAwEAAaN3MHUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
  1258  CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBCfkRYf
  1259  Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI
  1260  hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
  1261  ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
  1262  vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
  1263  -----END CERTIFICATE-----`
  1264  
  1265  const x509v1TestRoot = `-----BEGIN CERTIFICATE-----
  1266  MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
  1267  ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1
  1268  MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB
  1269  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
  1270  siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
  1271  +QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
  1272  JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
  1273  FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
  1274  EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAcIwqeNUpQr9cOcYm
  1275  YjpGpYkQ6b248xijCK7zI+lOeWN89zfSXn1AvfsC9pSdTMeDklWktbF/Ad0IN8Md
  1276  h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB
  1277  /1JmacUUofl+HusHuLkDxmadogI=
  1278  -----END CERTIFICATE-----`
  1279  
  1280  const x509v1TestIntermediate = `-----BEGIN CERTIFICATE-----
  1281  MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH
  1282  b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx
  1283  MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50
  1284  ZXJtZWRpYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ2QyniAOT+5YL
  1285  jeinEBJr3NsC/Q2QJ/VKmgvp+xRxuKTHJiVmxVijmp0vWg8AWfkmuE4p3hXQbbqM
  1286  k5yxrk1n60ONhim2L4VXriEvCE7X2OXhTmBls5Ufr7aqIgPMikwjScCXwz8E8qI8
  1287  UxyAhnjeJwMYBU8TuwBImSd4LBHoQQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAIab
  1288  DRG6FbF9kL9jb/TDHkbVBk+sl/Pxi4/XjuFyIALlARgAkeZcPmL5tNW1ImHkwsHR
  1289  zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur
  1290  x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+
  1291  -----END CERTIFICATE-----`
  1292  
  1293  const x509v1TestLeaf = `-----BEGIN CERTIFICATE-----
  1294  MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV
  1295  BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw
  1296  MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW
  1297  BgNVBAMTD2Zvby5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
  1298  gYEApUh60Z+a5/oKJxG//Dn8CihSo2CJHNIIO3zEJZ1EeNSMZCynaIR6D3IPZEIR
  1299  +RG2oGt+f5EEukAPYxwasp6VeZEezoQWJ+97nPCT6DpwLlWp3i2MF8piK2R9vxkG
  1300  Z5n0+HzYk1VM8epIrZFUXSMGTX8w1y041PX/yYLxbdEifdcCAwEAAaNaMFgwDgYD
  1301  VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
  1302  HRMBAf8EAjAAMBkGA1UdDgQSBBBFozXe0SnzAmjy+1U6M/cvMA0GCSqGSIb3DQEB
  1303  CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9
  1304  5R7siu+JnIFotA7IbBe633p75xEnLN88X626N/XRFG9iScLzpj0o0PWXBUiB+fxL
  1305  /jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/
  1306  -----END CERTIFICATE-----`
  1307  
  1308  const ignoreCNWithSANRoot = `-----BEGIN CERTIFICATE-----
  1309  MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE
  1310  ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx
  1311  MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa
  1312  BgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
  1313  DwAwggEKAoIBAQC4YAf5YqlXGcikvbMWtVrNICt+V/NNWljwfvSKdg4Inm7k6BwW
  1314  P6y4Y+n4qSYIWNU4iRkdpajufzctxQCO6ty13iw3qVktzcC5XBIiS6ymiRhhDgnY
  1315  VQqyakVGw9MxrPwdRZVlssUv3Hmy6tU+v5Ok31SLY5z3wKgYWvSyYs0b8bKNU8kf
  1316  2FmSHnBN16lxGdjhe3ji58F/zFMr0ds+HakrLIvVdFcQFAnQopM8FTHpoWNNzGU3
  1317  KaiO0jBbMFkd6uVjVnuRJ+xjuiqi/NWwiwQA+CEr9HKzGkxOF8nAsHamdmO1wW+w
  1318  OsCrC0qWQ/f5NTOVATTJe0vj88OMTvo3071VAgMBAAGjXTBbMA4GA1UdDwEB/wQE
  1319  AwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw
  1320  AwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOC
  1321  AQEAGOn3XjxHyHbXLKrRmpwV447B7iNBXR5VlhwOgt1kWaHDL2+8f/9/h0HMkB6j
  1322  fC+/yyuYVqYuOeavqMGVrh33D2ODuTQcFlOx5lXukP46j3j+Lm0jjZ1qNX7vlP8I
  1323  VlUXERhbelkw8O4oikakwIY9GE8syuSgYf+VeBW/lvuAZQrdnPfabxe05Tre6RXy
  1324  nJHMB1q07YHpbwIkcV/lfCE9pig2nPXTLwYZz9cl46Ul5RCpPUi+IKURo3x8y0FU
  1325  aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu
  1326  BJ6bvwEAasFiLGP6Zbdmxb2hIA==
  1327  -----END CERTIFICATE-----`
  1328  
  1329  const ignoreCNWithSANLeaf = `-----BEGIN CERTIFICATE-----
  1330  MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV
  1331  BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw
  1332  MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw
  1333  FgYDVQQDEw9mb28uZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
  1334  ggEKAoIBAQDBqskp89V/JMIBBqcauKSOVLcMyIE/t0jgSWVrsI4sksBTabLsfMdS
  1335  ui2n+dHQ1dRBuw3o4g4fPrWwS3nMnV3pZUHEn2TPi5N1xkjTaxObXgKIY2GKmFP3
  1336  rJ9vYqHT6mT4K93kCHoRcmJWWySc7S3JAOhTcdB4G+tIdQJN63E+XRYQQfNrn5HZ
  1337  hxQoOzaguHFx+ZGSD4Ntk6BSZz5NfjqCYqYxe+iCpTpEEYhIpi8joSPSmkTMTxBW
  1338  S1W2gXbYNQ9KjNkGM6FnQsUJrSPMrWs4v3UB/U88N5LkZeF41SqD9ySFGwbGajFV
  1339  nyzj12+4K4D8BLhlOc0Eo/F/8GwOwvmxAgMBAAGjgYkwgYYwDgYDVR0PAQH/BAQD
  1340  AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
  1341  MBkGA1UdDgQSBBCjeab27q+5pV43jBGANOJ1MBsGA1UdIwQUMBKAEEA31wH7QC+4
  1342  HH5UBCeMWQEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGZfZ
  1343  ErTVxxpIg64s22mQpXSk/72THVQsfsKHzlXmztM0CJzH8ccoN67ZqKxJCfdiE/FI
  1344  Emb6BVV4cGPeIKpcxaM2dwX/Y+Y0JaxpQJvqLxs+EByRL0gPP3shgg86WWCjYLxv
  1345  AgOn862d/JXGDrC9vIlQ/DDQcyL5g0JV5UjG2G9TUigbnrXxBw7BoWK6wmoSaHnR
  1346  sZKEHSs3RUJvm7qqpA9Yfzm9jg+i9j32zh1xFacghAOmFRFXa9eCVeigZ/KK2mEY
  1347  j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn
  1348  xZbqP3Krgjj4XNaXjg==
  1349  -----END CERTIFICATE-----`
  1350  
  1351  const excludedNamesLeaf = `-----BEGIN CERTIFICATE-----
  1352  MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE
  1353  BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
  1354  MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
  1355  ICgzNzM0NTE1NTYyODA2Mzk3KTEhMB8GA1UEAwwYSW50ZXJtZWRpYXRlIENBIGZv
  1356  ciAzMzkyMB4XDTE3MDIwODIxMTUwNFoXDTE4MDIwODIwMjQ1OFowgZAxCzAJBgNV
  1357  BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlMb3MgR2F0b3Mx
  1358  FDASBgNVBAoMC05ldGZsaXggSW5jMS0wKwYDVQQLDCRQbGF0Zm9ybSBTZWN1cml0
  1359  eSAoMzczNDUxNTc0ODUwMjY5NikxEzARBgNVBAMMCjE3Mi4xNi4wLjEwggEiMA0G
  1360  CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ0oP1bMv6bOeqcKbzinnGpNOpenhA
  1361  zdFFsgea62znWsH3Wg4+1Md8uPCqlaQIsaJQKZHc50eKD3bg0Io7c6kxHkBQr1b8
  1362  Q7cGeK3CjdqG3NwS/aizzrLKOwL693hFwwy7JY7GGCvogbhyQRKn6iV0U9zMm7bu
  1363  /9pQVV/wx8u01u2uAlLttjyQ5LJkxo5t8cATFVqxdN5J9eY//VSDiTwXnlpQITBP
  1364  /Ow+zYuZ3kFlzH3CtCOhOEvNG3Ar1NvP3Icq35PlHV+Eki4otnKfixwByoiGpqCB
  1365  UEIY04VrZJjwBxk08y/3jY2B3VLYGgi+rryyCxIqkB7UpSNPMMWSG4UpAgMBAAGj
  1366  LzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0RBBYwFIIMYmVuZGVyLmxvY2FshwSsEAAB
  1367  MA0GCSqGSIb3DQEBCwUAA4IBAQCLW3JO8L7LKByjzj2RciPjCGH5XF87Wd20gYLq
  1368  sNKcFwCIeyZhnQy5aZ164a5G9AIk2HLvH6HevBFPhA9Ivmyv/wYEfnPd1VcFkpgP
  1369  hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt
  1370  qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+
  1371  VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4
  1372  oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A
  1373  -----END CERTIFICATE-----`
  1374  
  1375  const excludedNamesIntermediate = `-----BEGIN CERTIFICATE-----
  1376  MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE
  1377  BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
  1378  MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
  1379  ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBmb3IgMzM5
  1380  MjAeFw0xNzAyMDgyMTE1MDRaFw0xODAyMDgyMDI0NThaMIGeMQswCQYDVQQGEwJV
  1381  UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJTG9zIEdhdG9zMRQwEgYD
  1382  VQQKDAtOZXRmbGl4IEluYzEtMCsGA1UECwwkUGxhdGZvcm0gU2VjdXJpdHkgKDM3
  1383  MzQ1MTU1NjI4MDYzOTcpMSEwHwYDVQQDDBhJbnRlcm1lZGlhdGUgQ0EgZm9yIDMz
  1384  OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCOyEs6tJ/t9emQTvlx
  1385  3FS7uJSou5rKkuqVxZdIuYQ+B2ZviBYUnMRT9bXDB0nsVdKZdp0hdchdiwNXDG/I
  1386  CiWu48jkcv/BdynVyayOT+0pOJSYLaPYpzBx1Pb9M5651ct9GSbj6Tz0ChVonoIE
  1387  1AIZ0kkebucZRRFHd0xbAKVRKyUzPN6HJ7WfgyauUp7RmlC35wTmrmARrFohQLlL
  1388  7oICy+hIQePMy9x1LSFTbPxZ5AUUXVC3eUACU3vLClF/Xs8XGHebZpUXCdMQjOGS
  1389  nq1eFguFHR1poSB8uSmmLqm4vqUH9CDhEgiBAC8yekJ8//kZQ7lUEqZj3YxVbk+Y
  1390  E4H5AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
  1391  ADxrnmNX5gWChgX9K5fYwhFDj5ofxZXAKVQk+WjmkwMcmCx3dtWSm++Wdksj/ZlA
  1392  V1cLW3ohWv1/OAZuOlw7sLf98aJpX+UUmIYYQxDubq+4/q7VA7HzEf2k/i/oN1NI
  1393  JgtrhpPcZ/LMO6k7DYx0qlfYq8pTSfd6MI4LnWKgLc+JSPJJjmvspgio2ZFcnYr7
  1394  A264BwLo6v1Mos1o1JUvFFcp4GANlw0XFiWh7JXYRl8WmS5DoouUC+aNJ3lmyF6z
  1395  LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS
  1396  zMBX1/lk4wkFckeUIlkD55Y=
  1397  -----END CERTIFICATE-----`
  1398  
  1399  const excludedNamesRoot = `-----BEGIN CERTIFICATE-----
  1400  MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE
  1401  BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
  1402  MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
  1403  ICgzNzMxNTA5NDM3NDYyNDg1KTEmMCQGA1UEAwwdTmFtZSBDb25zdHJhaW50cyBU
  1404  ZXN0IFJvb3QgQ0EwHhcNMTcwMjA4MjExNTA0WhcNMTgwMjA4MjAyNDU4WjCBmTEL
  1405  MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBH
  1406  YXRvczEUMBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNl
  1407  Y3VyaXR5ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBm
  1408  b3IgMzM5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJymcnX29ekc
  1409  7+MLyr8QuAzoHWznmGdDd2sITwWRjM89/21cdlHCGKSpULUNdFp9HDLWvYECtxt+
  1410  8TuzKiQz7qAerzGUT1zI5McIjHy0e/i4xIkfiBiNeTCuB/N9QRbZlcfM80ErkaA4
  1411  gCAFK8qZAcWkHIl6e+KaQFMPLKk9kckgAnVDHEJe8oLNCogCJ15558b65g05p9eb
  1412  5Lg+E98hoPRTQaDwlz3CZPfTTA2EiEZInSi8qzodFCbTpJUVTbiVUH/JtVjlibbb
  1413  smdcx5PORK+8ZJkhLEh54AjaWOX4tB/7Tkk8stg2VBmrIARt/j4UVj7cTrIWU3bV
  1414  m8TwHJG+YgsCAwEAAaNaMFgwDwYDVR0TAQH/BAUwAwEB/zBFBgNVHR4EPjA8oBww
  1415  CocICgEAAP//AAAwDoIMYmVuZGVyLmxvY2FsoRwwCocICgEAAP//AAAwDoIMYmVu
  1416  ZGVyLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAMjbheffPxtSKSv9NySW+8qmHs
  1417  n7Mb5GGyCFu+cMZSoSaabstbml+zHEFJvWz6/1E95K4F8jKhAcu/CwDf4IZrSD2+
  1418  Hee0DolVSQhZpnHgPyj7ZATz48e3aJaQPUlhCEOh0wwF4Y0N4FV0t7R6woLylYRZ
  1419  yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT
  1420  6mOAFN0qFb4RGzfGJW7x6z7KCULS7qVDp6fU3tRoScHFEgRubks6jzQ1W5ooSm4o
  1421  +NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy
  1422  -----END CERTIFICATE-----`
  1423  
  1424  const invalidCNRoot = `-----BEGIN CERTIFICATE-----
  1425  MIIBFjCBvgIJAIsu4r+jb70UMAoGCCqGSM49BAMCMBQxEjAQBgNVBAsMCVRlc3Qg
  1426  cm9vdDAeFw0xODA3MTExODMyMzVaFw0yODA3MDgxODMyMzVaMBQxEjAQBgNVBAsM
  1427  CVRlc3Qgcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF6oDgMg0LV6YhPj
  1428  QXaPXYCc2cIyCdqp0ROUksRz0pOLTc5iY2nraUheRUD1vRRneq7GeXOVNn7uXONg
  1429  oCGMjNwwCgYIKoZIzj0EAwIDRwAwRAIgDSiwgIn8g1lpruYH0QD1GYeoWVunfmrI
  1430  XzZZl0eW/ugCICgOfXeZ2GGy3wIC0352BaC3a8r5AAb2XSGNe+e9wNN6
  1431  -----END CERTIFICATE-----`
  1432  
  1433  const validCNWithoutSAN = `-----BEGIN CERTIFICATE-----
  1434  MIIBJzCBzwIUB7q8t9mrDAL+UB1OFaMN5BEWFKQwCgYIKoZIzj0EAwIwFDESMBAG
  1435  A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4NDcyNFoXDTI4MDcwODE4NDcyNFow
  1436  GjEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
  1437  AQcDQgAEp6Z8IjOnR38Iky1fYTUu2kVndvKXcxiwARJKGtW3b0E8uwVp9AZd/+sr
  1438  p4ULTPdFToFAeqnGHbu62bkms8pQkDAKBggqhkjOPQQDAgNHADBEAiBTbNe3WWFR
  1439  cqUYo0sNUuoV+tCTMDJUS+0PWIW4qBqCOwIgFHdLDn5PCk9kJpfc0O2qZx03hdq0
  1440  h7olHCpY9yMRiz0=
  1441  -----END CERTIFICATE-----`
  1442  
  1443  const rootWithoutSKID = `-----BEGIN CERTIFICATE-----
  1444  MIIBbzCCARSgAwIBAgIQeCkq3C8SOX/JM5PqYTl9cDAKBggqhkjOPQQDAjASMRAw
  1445  DgYDVQQKEwdBY21lIENvMB4XDTE5MDIwNDIyNTYzNFoXDTI5MDIwMTIyNTYzNFow
  1446  EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABISm
  1447  jGlTr4dLOWT+BCTm2PzWRjk1DpLcSAh+Al8eB1Nc2eBWxYIH9qPirfatvqBOA4c5
  1448  ZwycRpFoaw6O+EmXnVujTDBKMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
  1449  BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBIGA1UdEQQLMAmCB2V4YW1wbGUwCgYI
  1450  KoZIzj0EAwIDSQAwRgIhAMaBYWFCjTfn0MNyQ0QXvYT/iIFompkIqzw6wB7qjLrA
  1451  AiEA3sn65V7G4tsjZEOpN0Jykn9uiTjqniqn/S/qmv8gIec=
  1452  -----END CERTIFICATE-----`
  1453  
  1454  const leafWithAKID = `-----BEGIN CERTIFICATE-----
  1455  MIIBjTCCATSgAwIBAgIRAPCKYvADhKLPaWOtcTu2XYwwCgYIKoZIzj0EAwIwEjEQ
  1456  MA4GA1UEChMHQWNtZSBDbzAeFw0xOTAyMDQyMzA2NTJaFw0yOTAyMDEyMzA2NTJa
  1457  MBMxETAPBgNVBAoTCEFjbWUgTExDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
  1458  Wk5N+/8X97YT6ClFNIE5/4yc2YwKn921l0wrIJEcT2u+Uydm7EqtCJNtZjYMAnBd
  1459  Acp/wynpTwC6tBTsxcM0s6NqMGgwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
  1460  CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUwitfkXg0JglCjW9R
  1461  ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
  1462  4LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU
  1463  ZZMqeJS7JldLx91sPUArY5A=
  1464  -----END CERTIFICATE-----`
  1465  
  1466  const rootMatchingSKIDMismatchingSubject = `-----BEGIN CERTIFICATE-----
  1467  MIIBQjCB6aADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQTAe
  1468  Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
  1469  QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPK4p1uXq2aAeDtKDHIokg2rTcPM
  1470  2gq3N9Y96wiW6/7puBK1+INEW//cO9x6FpzkcsHw/TriAqy4sck/iDAvf9WjMjAw
  1471  MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAMBgNVHQ4EBQQDAQID
  1472  MAoGCCqGSM49BAMCA0gAMEUCIQDgtAp7iVHxMnKxZPaLQPC+Tv2r7+DJc88k2SKH
  1473  MPs/wQIgFjjNvBoQEl7vSHTcRGCCcFMdlN4l0Dqc9YwGa9fyrQs=
  1474  -----END CERTIFICATE-----`
  1475  
  1476  const rootMismatchingSKIDMatchingSubject = `-----BEGIN CERTIFICATE-----
  1477  MIIBNDCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
  1478  Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
  1479  QjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI1YRFcIlkWzm9BdEVrIsEQJ2dT6
  1480  qiW8/WV9GoIhmDtX9SEDHospc0Cgm+TeD2QYW2iMrS5mvNe4GSw0Jezg/bOjJDAi
  1481  MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNI
  1482  ADBFAiEAukWOiuellx8bugRiwCS5XQ6IOJ1SZcjuZxj76WojwxkCIHqa71qNw8FM
  1483  DtA5yoL9M2pDFF6ovFWnaCe+KlzSwAW/
  1484  -----END CERTIFICATE-----`
  1485  
  1486  const leafMatchingAKIDMatchingIssuer = `-----BEGIN CERTIFICATE-----
  1487  MIIBNTCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
  1488  Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMA8xDTALBgNVBAMTBExlYWYw
  1489  WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASNWERXCJZFs5vQXRFayLBECdnU+qol
  1490  vP1lfRqCIZg7V/UhAx6LKXNAoJvk3g9kGFtojK0uZrzXuBksNCXs4P2zoyYwJDAO
  1491  BgNVHSMEBzAFgAMBAgMwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNJ
  1492  ADBGAiEAnV9XV7a4h0nfJB8pWv+pBUXRlRFA2uZz3mXEpee8NYACIQCWa+wL70GL
  1493  ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA==
  1494  -----END CERTIFICATE-----`
  1495  
  1496  var unknownAuthorityErrorTests = []struct {
  1497  	name     string
  1498  	cert     string
  1499  	expected string
  1500  }{
  1501  	{"self-signed, cn", selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
  1502  	{"self-signed, no cn, org", selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
  1503  	{"self-signed, no cn, no org", selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
  1504  }
  1505  
  1506  func TestUnknownAuthorityError(t *testing.T) {
  1507  	for i, tt := range unknownAuthorityErrorTests {
  1508  		t.Run(tt.name, func(t *testing.T) {
  1509  			der, _ := pem.Decode([]byte(tt.cert))
  1510  			if der == nil {
  1511  				t.Fatalf("#%d: Unable to decode PEM block", i)
  1512  			}
  1513  			c, err := ParseCertificate(der.Bytes)
  1514  			if err != nil {
  1515  				t.Fatalf("#%d: Unable to parse certificate -> %v", i, err)
  1516  			}
  1517  			uae := &UnknownAuthorityError{
  1518  				Cert:     c,
  1519  				hintErr:  fmt.Errorf("empty"),
  1520  				hintCert: c,
  1521  			}
  1522  			actual := uae.Error()
  1523  			if actual != tt.expected {
  1524  				t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
  1525  			}
  1526  		})
  1527  	}
  1528  }
  1529  
  1530  var nameConstraintTests = []struct {
  1531  	constraint, domain string
  1532  	expectError        bool
  1533  	shouldMatch        bool
  1534  }{
  1535  	{"", "anything.com", false, true},
  1536  	{"example.com", "example.com", false, true},
  1537  	{"example.com.", "example.com", true, false},
  1538  	{"example.com", "example.com.", true, false},
  1539  	{"example.com", "ExAmPle.coM", false, true},
  1540  	{"example.com", "exampl1.com", false, false},
  1541  	{"example.com", "www.ExAmPle.coM", false, true},
  1542  	{"example.com", "sub.www.ExAmPle.coM", false, true},
  1543  	{"example.com", "notexample.com", false, false},
  1544  	{".example.com", "example.com", false, false},
  1545  	{".example.com", "www.example.com", false, true},
  1546  	{".example.com", "www..example.com", true, false},
  1547  }
  1548  
  1549  func TestNameConstraints(t *testing.T) {
  1550  	for i, test := range nameConstraintTests {
  1551  		result, err := matchDomainConstraint(test.domain, test.constraint)
  1552  
  1553  		if err != nil && !test.expectError {
  1554  			t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err)
  1555  			continue
  1556  		}
  1557  
  1558  		if err == nil && test.expectError {
  1559  			t.Errorf("unexpected success for test #%d: domain=%s, constraint=%s", i, test.domain, test.constraint)
  1560  			continue
  1561  		}
  1562  
  1563  		if result != test.shouldMatch {
  1564  			t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result)
  1565  		}
  1566  	}
  1567  }
  1568  
  1569  const selfSignedWithCommonName = `-----BEGIN CERTIFICATE-----
  1570  MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
  1571  MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw
  1572  CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
  1573  ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY
  1574  gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x
  1575  8RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH
  1576  +G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq
  1577  czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3
  1578  tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD
  1579  AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA
  1580  MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM
  1581  XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw
  1582  dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT
  1583  v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx
  1584  jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe
  1585  fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf
  1586  IuYkJwt6w+LH/9HZgf8=
  1587  -----END CERTIFICATE-----`
  1588  const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE-----
  1589  MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
  1590  MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw
  1591  CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa
  1592  7EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd
  1593  8t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS
  1594  gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/
  1595  xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu
  1596  g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU
  1597  46IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG
  1598  CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG
  1599  A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB
  1600  bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3
  1601  wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK
  1602  rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR
  1603  DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU
  1604  29ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w=
  1605  -----END CERTIFICATE-----`
  1606  const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE-----
  1607  MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
  1608  MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB
  1609  IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM
  1610  fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz
  1611  35YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI
  1612  2gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm
  1613  S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0
  1614  kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID
  1615  AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
  1616  AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN
  1617  BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq
  1618  4ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM
  1619  9z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb
  1620  w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
  1621  4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
  1622  8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
  1623  -----END CERTIFICATE-----`
  1624  
  1625  const criticalExtRoot = `-----BEGIN CERTIFICATE-----
  1626  MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
  1627  A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
  1628  MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
  1629  CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
  1630  gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
  1631  BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
  1632  /zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
  1633  uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
  1634  FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
  1635  -----END CERTIFICATE-----`
  1636  
  1637  const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
  1638  MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
  1639  A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
  1640  MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
  1641  KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
  1642  rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
  1643  AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
  1644  Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
  1645  EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
  1646  cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
  1647  xXbdbm27KQ==
  1648  -----END CERTIFICATE-----`
  1649  
  1650  const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
  1651  MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
  1652  A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
  1653  MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
  1654  bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
  1655  6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
  1656  gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
  1657  AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
  1658  IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
  1659  SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
  1660  I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
  1661  -----END CERTIFICATE-----`
  1662  
  1663  const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
  1664  MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
  1665  T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
  1666  MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
  1667  cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
  1668  mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
  1669  oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
  1670  BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
  1671  UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
  1672  BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
  1673  c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
  1674  -----END CERTIFICATE-----`
  1675  
  1676  const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
  1677  MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
  1678  A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
  1679  aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
  1680  T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
  1681  A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
  1682  GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
  1683  FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
  1684  UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
  1685  CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
  1686  2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
  1687  -----END CERTIFICATE-----`
  1688  
  1689  func TestValidHostname(t *testing.T) {
  1690  	tests := []struct {
  1691  		host                     string
  1692  		validInput, validPattern bool
  1693  	}{
  1694  		{host: "example.com", validInput: true, validPattern: true},
  1695  		{host: "eXample123-.com", validInput: true, validPattern: true},
  1696  		{host: "-eXample123-.com"},
  1697  		{host: ""},
  1698  		{host: "."},
  1699  		{host: "example..com"},
  1700  		{host: ".example.com"},
  1701  		{host: "example.com.", validInput: true},
  1702  		{host: "*.example.com."},
  1703  		{host: "*.example.com", validPattern: true},
  1704  		{host: "*foo.example.com"},
  1705  		{host: "foo.*.example.com"},
  1706  		{host: "exa_mple.com", validInput: true, validPattern: true},
  1707  		{host: "foo,bar"},
  1708  		{host: "project-dev:us-central1:main"},
  1709  	}
  1710  	for _, tt := range tests {
  1711  		if got := validHostnamePattern(tt.host); got != tt.validPattern {
  1712  			t.Errorf("validHostnamePattern(%q) = %v, want %v", tt.host, got, tt.validPattern)
  1713  		}
  1714  		if got := validHostnameInput(tt.host); got != tt.validInput {
  1715  			t.Errorf("validHostnameInput(%q) = %v, want %v", tt.host, got, tt.validInput)
  1716  		}
  1717  	}
  1718  }
  1719  
  1720  func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
  1721  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  1722  	if err != nil {
  1723  		return nil, nil, err
  1724  	}
  1725  
  1726  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
  1727  	serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
  1728  
  1729  	template := &Certificate{
  1730  		SerialNumber: serialNumber,
  1731  		Subject:      pkix.Name{CommonName: cn},
  1732  		NotBefore:    time.Now().Add(-1 * time.Hour),
  1733  		NotAfter:     time.Now().Add(24 * time.Hour),
  1734  
  1735  		KeyUsage:              KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
  1736  		ExtKeyUsage:           []ExtKeyUsage{ExtKeyUsageServerAuth},
  1737  		BasicConstraintsValid: true,
  1738  		IsCA:                  isCA,
  1739  	}
  1740  	if issuer == nil {
  1741  		issuer = template
  1742  		issuerKey = priv
  1743  	}
  1744  
  1745  	derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
  1746  	if err != nil {
  1747  		return nil, nil, err
  1748  	}
  1749  	cert, err := ParseCertificate(derBytes)
  1750  	if err != nil {
  1751  		return nil, nil, err
  1752  	}
  1753  
  1754  	return cert, priv, nil
  1755  }
  1756  
  1757  func TestPathologicalChain(t *testing.T) {
  1758  	if testing.Short() {
  1759  		t.Skip("skipping generation of a long chain of certificates in short mode")
  1760  	}
  1761  
  1762  	// Build a chain where all intermediates share the same subject, to hit the
  1763  	// path building worst behavior.
  1764  	roots, intermediates := NewCertPool(), NewCertPool()
  1765  
  1766  	parent, parentKey, err := generateCert("Root CA", true, nil, nil)
  1767  	if err != nil {
  1768  		t.Fatal(err)
  1769  	}
  1770  	roots.AddCert(parent)
  1771  
  1772  	for i := 1; i < 100; i++ {
  1773  		parent, parentKey, err = generateCert("Intermediate CA", true, parent, parentKey)
  1774  		if err != nil {
  1775  			t.Fatal(err)
  1776  		}
  1777  		intermediates.AddCert(parent)
  1778  	}
  1779  
  1780  	leaf, _, err := generateCert("Leaf", false, parent, parentKey)
  1781  	if err != nil {
  1782  		t.Fatal(err)
  1783  	}
  1784  
  1785  	start := time.Now()
  1786  	_, err = leaf.Verify(VerifyOptions{
  1787  		Roots:         roots,
  1788  		Intermediates: intermediates,
  1789  	})
  1790  	t.Logf("verification took %v", time.Since(start))
  1791  
  1792  	if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
  1793  		t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
  1794  	}
  1795  }
  1796  
  1797  func TestLongChain(t *testing.T) {
  1798  	if testing.Short() {
  1799  		t.Skip("skipping generation of a long chain of certificates in short mode")
  1800  	}
  1801  
  1802  	roots, intermediates := NewCertPool(), NewCertPool()
  1803  
  1804  	parent, parentKey, err := generateCert("Root CA", true, nil, nil)
  1805  	if err != nil {
  1806  		t.Fatal(err)
  1807  	}
  1808  	roots.AddCert(parent)
  1809  
  1810  	for i := 1; i < 15; i++ {
  1811  		name := fmt.Sprintf("Intermediate CA #%d", i)
  1812  		parent, parentKey, err = generateCert(name, true, parent, parentKey)
  1813  		if err != nil {
  1814  			t.Fatal(err)
  1815  		}
  1816  		intermediates.AddCert(parent)
  1817  	}
  1818  
  1819  	leaf, _, err := generateCert("Leaf", false, parent, parentKey)
  1820  	if err != nil {
  1821  		t.Fatal(err)
  1822  	}
  1823  
  1824  	start := time.Now()
  1825  	if _, err := leaf.Verify(VerifyOptions{
  1826  		Roots:         roots,
  1827  		Intermediates: intermediates,
  1828  	}); err != nil {
  1829  		t.Error(err)
  1830  	}
  1831  	t.Logf("verification took %v", time.Since(start))
  1832  }
  1833  
  1834  func TestSystemRootsError(t *testing.T) {
  1835  	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
  1836  		t.Skip("Windows and darwin do not use (or support) systemRoots")
  1837  	}
  1838  
  1839  	defer func(oldSystemRoots *CertPool) { systemRoots = oldSystemRoots }(systemRootsPool())
  1840  
  1841  	opts := VerifyOptions{
  1842  		Intermediates: NewCertPool(),
  1843  		DNSName:       "www.google.com",
  1844  		CurrentTime:   time.Unix(1677615892, 0),
  1845  	}
  1846  
  1847  	if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok {
  1848  		t.Fatalf("failed to parse intermediate")
  1849  	}
  1850  
  1851  	leaf, err := certificateFromPEM(googleLeaf)
  1852  	if err != nil {
  1853  		t.Fatalf("failed to parse leaf: %v", err)
  1854  	}
  1855  
  1856  	systemRoots = nil
  1857  
  1858  	_, err = leaf.Verify(opts)
  1859  	if _, ok := err.(SystemRootsError); !ok {
  1860  		t.Errorf("error was not SystemRootsError: %v", err)
  1861  	}
  1862  }
  1863  
  1864  func TestSystemRootsErrorUnwrap(t *testing.T) {
  1865  	var err1 = errors.New("err1")
  1866  	err := SystemRootsError{Err: err1}
  1867  	if !errors.Is(err, err1) {
  1868  		t.Error("errors.Is failed, wanted success")
  1869  	}
  1870  }
  1871  
  1872  func macosMajorVersion(t *testing.T) (int, error) {
  1873  	cmd := testenv.Command(t, "sw_vers", "-productVersion")
  1874  	out, err := cmd.Output()
  1875  	if err != nil {
  1876  		if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
  1877  			return 0, fmt.Errorf("%v: %v\n%s", cmd, err, ee.Stderr)
  1878  		}
  1879  		return 0, fmt.Errorf("%v: %v", cmd, err)
  1880  	}
  1881  	before, _, ok := strings.Cut(string(out), ".")
  1882  	major, err := strconv.Atoi(before)
  1883  	if !ok || err != nil {
  1884  		return 0, fmt.Errorf("%v: unexpected output: %q", cmd, out)
  1885  	}
  1886  
  1887  	return major, nil
  1888  }
  1889  
  1890  func TestIssue51759(t *testing.T) {
  1891  	if runtime.GOOS != "darwin" {
  1892  		t.Skip("only affects darwin")
  1893  	}
  1894  
  1895  	testenv.MustHaveExecPath(t, "sw_vers")
  1896  	if vers, err := macosMajorVersion(t); err != nil {
  1897  		if builder := testenv.Builder(); builder != "" {
  1898  			t.Fatalf("unable to determine macOS version: %s", err)
  1899  		} else {
  1900  			t.Skip("unable to determine macOS version")
  1901  		}
  1902  	} else if vers < 11 {
  1903  		t.Skip("behavior only enforced in macOS 11 and after")
  1904  	}
  1905  
  1906  	// badCertData contains a cert that we parse as valid
  1907  	// but that macOS SecCertificateCreateWithData rejects.
  1908  	const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r"
  1909  	badCert, err := ParseCertificate([]byte(badCertData))
  1910  	if err != nil {
  1911  		t.Fatal(err)
  1912  	}
  1913  
  1914  	t.Run("leaf", func(t *testing.T) {
  1915  		opts := VerifyOptions{}
  1916  		expectedErr := "invalid leaf certificate"
  1917  		_, err = badCert.Verify(opts)
  1918  		if err == nil || err.Error() != expectedErr {
  1919  			t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
  1920  		}
  1921  	})
  1922  
  1923  	goodCert, err := certificateFromPEM(googleLeaf)
  1924  	if err != nil {
  1925  		t.Fatal(err)
  1926  	}
  1927  
  1928  	t.Run("intermediate", func(t *testing.T) {
  1929  		opts := VerifyOptions{
  1930  			Intermediates: NewCertPool(),
  1931  		}
  1932  		opts.Intermediates.AddCert(badCert)
  1933  		expectedErr := "SecCertificateCreateWithData: invalid certificate"
  1934  		_, err = goodCert.Verify(opts)
  1935  		if err == nil || err.Error() != expectedErr {
  1936  			t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
  1937  		}
  1938  	})
  1939  }
  1940  
  1941  type trustGraphEdge struct {
  1942  	Issuer         string
  1943  	Subject        string
  1944  	Type           int
  1945  	MutateTemplate func(*Certificate)
  1946  	Constraint     func([]*Certificate) error
  1947  }
  1948  
  1949  type rootDescription struct {
  1950  	Subject        string
  1951  	MutateTemplate func(*Certificate)
  1952  	Constraint     func([]*Certificate) error
  1953  }
  1954  
  1955  type trustGraphDescription struct {
  1956  	Roots []rootDescription
  1957  	Leaf  string
  1958  	Graph []trustGraphEdge
  1959  }
  1960  
  1961  func genCertEdge(t *testing.T, subject string, key crypto.Signer, mutateTmpl func(*Certificate), certType int, issuer *Certificate, signer crypto.Signer) *Certificate {
  1962  	t.Helper()
  1963  
  1964  	serial, err := rand.Int(rand.Reader, big.NewInt(100))
  1965  	if err != nil {
  1966  		t.Fatalf("failed to generate test serial: %s", err)
  1967  	}
  1968  	tmpl := &Certificate{
  1969  		SerialNumber: serial,
  1970  		Subject:      pkix.Name{CommonName: subject},
  1971  		NotBefore:    time.Now().Add(-time.Hour),
  1972  		NotAfter:     time.Now().Add(time.Hour),
  1973  	}
  1974  	if certType == rootCertificate || certType == intermediateCertificate {
  1975  		tmpl.IsCA, tmpl.BasicConstraintsValid = true, true
  1976  		tmpl.KeyUsage = KeyUsageCertSign
  1977  	} else if certType == leafCertificate {
  1978  		tmpl.DNSNames = []string{"localhost"}
  1979  	}
  1980  	if mutateTmpl != nil {
  1981  		mutateTmpl(tmpl)
  1982  	}
  1983  
  1984  	if certType == rootCertificate {
  1985  		issuer = tmpl
  1986  		signer = key
  1987  	}
  1988  
  1989  	d, err := CreateCertificate(rand.Reader, tmpl, issuer, key.Public(), signer)
  1990  	if err != nil {
  1991  		t.Fatalf("failed to generate test cert: %s", err)
  1992  	}
  1993  	c, err := ParseCertificate(d)
  1994  	if err != nil {
  1995  		t.Fatalf("failed to parse test cert: %s", err)
  1996  	}
  1997  	return c
  1998  }
  1999  
  2000  func buildTrustGraph(t *testing.T, d trustGraphDescription) (*CertPool, *CertPool, *Certificate) {
  2001  	t.Helper()
  2002  
  2003  	certs := map[string]*Certificate{}
  2004  	keys := map[string]crypto.Signer{}
  2005  	rootPool := NewCertPool()
  2006  	for _, r := range d.Roots {
  2007  		k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2008  		if err != nil {
  2009  			t.Fatalf("failed to generate test key: %s", err)
  2010  		}
  2011  		root := genCertEdge(t, r.Subject, k, r.MutateTemplate, rootCertificate, nil, nil)
  2012  		if r.Constraint != nil {
  2013  			rootPool.AddCertWithConstraint(root, r.Constraint)
  2014  		} else {
  2015  			rootPool.AddCert(root)
  2016  		}
  2017  		certs[r.Subject] = root
  2018  		keys[r.Subject] = k
  2019  	}
  2020  
  2021  	intermediatePool := NewCertPool()
  2022  	var leaf *Certificate
  2023  	for _, e := range d.Graph {
  2024  		issuerCert, ok := certs[e.Issuer]
  2025  		if !ok {
  2026  			t.Fatalf("unknown issuer %s", e.Issuer)
  2027  		}
  2028  		issuerKey, ok := keys[e.Issuer]
  2029  		if !ok {
  2030  			t.Fatalf("unknown issuer %s", e.Issuer)
  2031  		}
  2032  
  2033  		k, ok := keys[e.Subject]
  2034  		if !ok {
  2035  			var err error
  2036  			k, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2037  			if err != nil {
  2038  				t.Fatalf("failed to generate test key: %s", err)
  2039  			}
  2040  			keys[e.Subject] = k
  2041  		}
  2042  		cert := genCertEdge(t, e.Subject, k, e.MutateTemplate, e.Type, issuerCert, issuerKey)
  2043  		certs[e.Subject] = cert
  2044  		if e.Subject == d.Leaf {
  2045  			leaf = cert
  2046  		} else {
  2047  			if e.Constraint != nil {
  2048  				intermediatePool.AddCertWithConstraint(cert, e.Constraint)
  2049  			} else {
  2050  				intermediatePool.AddCert(cert)
  2051  			}
  2052  		}
  2053  	}
  2054  
  2055  	return rootPool, intermediatePool, leaf
  2056  }
  2057  
  2058  func chainsToStrings(chains [][]*Certificate) []string {
  2059  	chainStrings := []string{}
  2060  	for _, chain := range chains {
  2061  		names := []string{}
  2062  		for _, c := range chain {
  2063  			names = append(names, c.Subject.String())
  2064  		}
  2065  		chainStrings = append(chainStrings, strings.Join(names, " -> "))
  2066  	}
  2067  	slices.Sort(chainStrings)
  2068  	return chainStrings
  2069  }
  2070  
  2071  func TestPathBuilding(t *testing.T) {
  2072  	tests := []struct {
  2073  		name           string
  2074  		graph          trustGraphDescription
  2075  		expectedChains []string
  2076  		expectedErr    string
  2077  	}{
  2078  		{
  2079  			// Build the following graph from RFC 4158, figure 7 (note that in this graph edges represent
  2080  			// certificates where the parent is the issuer and the child is the subject.) For the certificate
  2081  			// C->B, use an unsupported ExtKeyUsage (in this case ExtKeyUsageCodeSigning) which invalidates
  2082  			// the path Trust Anchor -> C -> B -> EE. The remaining valid paths should be:
  2083  			//   * Trust Anchor -> A -> B -> EE
  2084  			//   * Trust Anchor -> C -> A -> B -> EE
  2085  			//
  2086  			//     +---------+
  2087  			//     |  Trust  |
  2088  			//     | Anchor  |
  2089  			//     +---------+
  2090  			//      |       |
  2091  			//      v       v
  2092  			//   +---+    +---+
  2093  			//   | A |<-->| C |
  2094  			//   +---+    +---+
  2095  			//    |         |
  2096  			//    |  +---+  |
  2097  			//    +->| B |<-+
  2098  			//       +---+
  2099  			//         |
  2100  			//         v
  2101  			//       +----+
  2102  			//       | EE |
  2103  			//       +----+
  2104  			name: "bad EKU",
  2105  			graph: trustGraphDescription{
  2106  				Roots: []rootDescription{{Subject: "root"}},
  2107  				Leaf:  "leaf",
  2108  				Graph: []trustGraphEdge{
  2109  					{
  2110  						Issuer:  "root",
  2111  						Subject: "inter a",
  2112  						Type:    intermediateCertificate,
  2113  					},
  2114  					{
  2115  						Issuer:  "root",
  2116  						Subject: "inter c",
  2117  						Type:    intermediateCertificate,
  2118  					},
  2119  					{
  2120  						Issuer:  "inter c",
  2121  						Subject: "inter a",
  2122  						Type:    intermediateCertificate,
  2123  					},
  2124  					{
  2125  						Issuer:  "inter a",
  2126  						Subject: "inter c",
  2127  						Type:    intermediateCertificate,
  2128  					},
  2129  					{
  2130  						Issuer:  "inter c",
  2131  						Subject: "inter b",
  2132  						Type:    intermediateCertificate,
  2133  						MutateTemplate: func(t *Certificate) {
  2134  							t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
  2135  						},
  2136  					},
  2137  					{
  2138  						Issuer:  "inter a",
  2139  						Subject: "inter b",
  2140  						Type:    intermediateCertificate,
  2141  					},
  2142  					{
  2143  						Issuer:  "inter b",
  2144  						Subject: "leaf",
  2145  						Type:    leafCertificate,
  2146  					},
  2147  				},
  2148  			},
  2149  			expectedChains: []string{
  2150  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
  2151  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
  2152  			},
  2153  		},
  2154  		{
  2155  			// Build the following graph from RFC 4158, figure 7 (note that in this graph edges represent
  2156  			// certificates where the parent is the issuer and the child is the subject.) For the certificate
  2157  			// C->B, use a unconstrained SAN which invalidates the path Trust Anchor -> C -> B -> EE. The
  2158  			// remaining valid paths should be:
  2159  			//   * Trust Anchor -> A -> B -> EE
  2160  			//   * Trust Anchor -> C -> A -> B -> EE
  2161  			//
  2162  			//     +---------+
  2163  			//     |  Trust  |
  2164  			//     | Anchor  |
  2165  			//     +---------+
  2166  			//      |       |
  2167  			//      v       v
  2168  			//   +---+    +---+
  2169  			//   | A |<-->| C |
  2170  			//   +---+    +---+
  2171  			//    |         |
  2172  			//    |  +---+  |
  2173  			//    +->| B |<-+
  2174  			//       +---+
  2175  			//         |
  2176  			//         v
  2177  			//       +----+
  2178  			//       | EE |
  2179  			//       +----+
  2180  			name: "bad EKU",
  2181  			graph: trustGraphDescription{
  2182  				Roots: []rootDescription{{Subject: "root"}},
  2183  				Leaf:  "leaf",
  2184  				Graph: []trustGraphEdge{
  2185  					{
  2186  						Issuer:  "root",
  2187  						Subject: "inter a",
  2188  						Type:    intermediateCertificate,
  2189  					},
  2190  					{
  2191  						Issuer:  "root",
  2192  						Subject: "inter c",
  2193  						Type:    intermediateCertificate,
  2194  					},
  2195  					{
  2196  						Issuer:  "inter c",
  2197  						Subject: "inter a",
  2198  						Type:    intermediateCertificate,
  2199  					},
  2200  					{
  2201  						Issuer:  "inter a",
  2202  						Subject: "inter c",
  2203  						Type:    intermediateCertificate,
  2204  					},
  2205  					{
  2206  						Issuer:  "inter c",
  2207  						Subject: "inter b",
  2208  						Type:    intermediateCertificate,
  2209  						MutateTemplate: func(t *Certificate) {
  2210  							t.PermittedDNSDomains = []string{"good"}
  2211  							t.DNSNames = []string{"bad"}
  2212  						},
  2213  					},
  2214  					{
  2215  						Issuer:  "inter a",
  2216  						Subject: "inter b",
  2217  						Type:    intermediateCertificate,
  2218  					},
  2219  					{
  2220  						Issuer:  "inter b",
  2221  						Subject: "leaf",
  2222  						Type:    leafCertificate,
  2223  					},
  2224  				},
  2225  			},
  2226  			expectedChains: []string{
  2227  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
  2228  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
  2229  			},
  2230  		},
  2231  		{
  2232  			// Build the following graph, we should find both paths:
  2233  			//   * Trust Anchor -> A -> C -> EE
  2234  			//   * Trust Anchor -> A -> B -> C -> EE
  2235  			//
  2236  			//	       +---------+
  2237  			//	       |  Trust  |
  2238  			//	       | Anchor  |
  2239  			//	       +---------+
  2240  			//	            |
  2241  			//	            v
  2242  			//	          +---+
  2243  			//	          | A |
  2244  			//	          +---+
  2245  			//	           | |
  2246  			//	           | +----+
  2247  			//	           |      v
  2248  			//	           |    +---+
  2249  			//	           |    | B |
  2250  			//	           |    +---+
  2251  			//	           |      |
  2252  			//	           |  +---v
  2253  			//	           v  v
  2254  			//            +---+
  2255  			//            | C |
  2256  			//            +---+
  2257  			//              |
  2258  			//              v
  2259  			//            +----+
  2260  			//            | EE |
  2261  			//            +----+
  2262  			name: "all paths",
  2263  			graph: trustGraphDescription{
  2264  				Roots: []rootDescription{{Subject: "root"}},
  2265  				Leaf:  "leaf",
  2266  				Graph: []trustGraphEdge{
  2267  					{
  2268  						Issuer:  "root",
  2269  						Subject: "inter a",
  2270  						Type:    intermediateCertificate,
  2271  					},
  2272  					{
  2273  						Issuer:  "inter a",
  2274  						Subject: "inter b",
  2275  						Type:    intermediateCertificate,
  2276  					},
  2277  					{
  2278  						Issuer:  "inter a",
  2279  						Subject: "inter c",
  2280  						Type:    intermediateCertificate,
  2281  					},
  2282  					{
  2283  						Issuer:  "inter b",
  2284  						Subject: "inter c",
  2285  						Type:    intermediateCertificate,
  2286  					},
  2287  					{
  2288  						Issuer:  "inter c",
  2289  						Subject: "leaf",
  2290  						Type:    leafCertificate,
  2291  					},
  2292  				},
  2293  			},
  2294  			expectedChains: []string{
  2295  				"CN=leaf -> CN=inter c -> CN=inter a -> CN=root",
  2296  				"CN=leaf -> CN=inter c -> CN=inter b -> CN=inter a -> CN=root",
  2297  			},
  2298  		},
  2299  		{
  2300  			// Build the following graph, which contains a cross-signature loop
  2301  			// (A and C cross sign each other). Paths that include the A -> C -> A
  2302  			// (and vice versa) loop should be ignored, resulting in the paths:
  2303  			//   * Trust Anchor -> A -> B -> EE
  2304  			//   * Trust Anchor -> C -> B -> EE
  2305  			//   * Trust Anchor -> A -> C -> B -> EE
  2306  			//   * Trust Anchor -> C -> A -> B -> EE
  2307  			//
  2308  			//     +---------+
  2309  			//     |  Trust  |
  2310  			//     | Anchor  |
  2311  			//     +---------+
  2312  			//      |       |
  2313  			//      v       v
  2314  			//   +---+    +---+
  2315  			//   | A |<-->| C |
  2316  			//   +---+    +---+
  2317  			//    |         |
  2318  			//    |  +---+  |
  2319  			//    +->| B |<-+
  2320  			//       +---+
  2321  			//         |
  2322  			//         v
  2323  			//       +----+
  2324  			//       | EE |
  2325  			//       +----+
  2326  			name: "ignore cross-sig loops",
  2327  			graph: trustGraphDescription{
  2328  				Roots: []rootDescription{{Subject: "root"}},
  2329  				Leaf:  "leaf",
  2330  				Graph: []trustGraphEdge{
  2331  					{
  2332  						Issuer:  "root",
  2333  						Subject: "inter a",
  2334  						Type:    intermediateCertificate,
  2335  					},
  2336  					{
  2337  						Issuer:  "root",
  2338  						Subject: "inter c",
  2339  						Type:    intermediateCertificate,
  2340  					},
  2341  					{
  2342  						Issuer:  "inter c",
  2343  						Subject: "inter a",
  2344  						Type:    intermediateCertificate,
  2345  					},
  2346  					{
  2347  						Issuer:  "inter a",
  2348  						Subject: "inter c",
  2349  						Type:    intermediateCertificate,
  2350  					},
  2351  					{
  2352  						Issuer:  "inter c",
  2353  						Subject: "inter b",
  2354  						Type:    intermediateCertificate,
  2355  					},
  2356  					{
  2357  						Issuer:  "inter a",
  2358  						Subject: "inter b",
  2359  						Type:    intermediateCertificate,
  2360  					},
  2361  					{
  2362  						Issuer:  "inter b",
  2363  						Subject: "leaf",
  2364  						Type:    leafCertificate,
  2365  					},
  2366  				},
  2367  			},
  2368  			expectedChains: []string{
  2369  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
  2370  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
  2371  				"CN=leaf -> CN=inter b -> CN=inter c -> CN=inter a -> CN=root",
  2372  				"CN=leaf -> CN=inter b -> CN=inter c -> CN=root",
  2373  			},
  2374  		},
  2375  		{
  2376  			// Build a simple two node graph, where the leaf is directly issued from
  2377  			// the root and both certificates have matching subject and public key, but
  2378  			// the leaf has SANs.
  2379  			name: "leaf with same subject, key, as parent but with SAN",
  2380  			graph: trustGraphDescription{
  2381  				Roots: []rootDescription{{Subject: "root"}},
  2382  				Leaf:  "root",
  2383  				Graph: []trustGraphEdge{
  2384  					{
  2385  						Issuer:  "root",
  2386  						Subject: "root",
  2387  						Type:    leafCertificate,
  2388  						MutateTemplate: func(c *Certificate) {
  2389  							c.DNSNames = []string{"localhost"}
  2390  						},
  2391  					},
  2392  				},
  2393  			},
  2394  			expectedChains: []string{
  2395  				"CN=root -> CN=root",
  2396  			},
  2397  		},
  2398  		{
  2399  			// Build a basic graph with two paths from leaf to root, but the path passing
  2400  			// through C should be ignored, because it has invalid EKU nesting.
  2401  			name: "ignore invalid EKU path",
  2402  			graph: trustGraphDescription{
  2403  				Roots: []rootDescription{{Subject: "root"}},
  2404  				Leaf:  "leaf",
  2405  				Graph: []trustGraphEdge{
  2406  					{
  2407  						Issuer:  "root",
  2408  						Subject: "inter a",
  2409  						Type:    intermediateCertificate,
  2410  					},
  2411  					{
  2412  						Issuer:  "root",
  2413  						Subject: "inter c",
  2414  						Type:    intermediateCertificate,
  2415  					},
  2416  					{
  2417  						Issuer:  "inter c",
  2418  						Subject: "inter b",
  2419  						Type:    intermediateCertificate,
  2420  						MutateTemplate: func(t *Certificate) {
  2421  							t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
  2422  						},
  2423  					},
  2424  					{
  2425  						Issuer:  "inter a",
  2426  						Subject: "inter b",
  2427  						Type:    intermediateCertificate,
  2428  						MutateTemplate: func(t *Certificate) {
  2429  							t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
  2430  						},
  2431  					},
  2432  					{
  2433  						Issuer:  "inter b",
  2434  						Subject: "leaf",
  2435  						Type:    leafCertificate,
  2436  						MutateTemplate: func(t *Certificate) {
  2437  							t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
  2438  						},
  2439  					},
  2440  				},
  2441  			},
  2442  			expectedChains: []string{
  2443  				"CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
  2444  			},
  2445  		},
  2446  		{
  2447  			// A name constraint on the root should apply to any names that appear
  2448  			// on the intermediate, meaning there is no valid chain.
  2449  			name: "constrained root, invalid intermediate",
  2450  			graph: trustGraphDescription{
  2451  				Roots: []rootDescription{
  2452  					{
  2453  						Subject: "root",
  2454  						MutateTemplate: func(t *Certificate) {
  2455  							t.PermittedDNSDomains = []string{"example.com"}
  2456  						},
  2457  					},
  2458  				},
  2459  				Leaf: "leaf",
  2460  				Graph: []trustGraphEdge{
  2461  					{
  2462  						Issuer:  "root",
  2463  						Subject: "inter",
  2464  						Type:    intermediateCertificate,
  2465  						MutateTemplate: func(t *Certificate) {
  2466  							t.DNSNames = []string{"beep.com"}
  2467  						},
  2468  					},
  2469  					{
  2470  						Issuer:  "inter",
  2471  						Subject: "leaf",
  2472  						Type:    leafCertificate,
  2473  						MutateTemplate: func(t *Certificate) {
  2474  							t.DNSNames = []string{"www.example.com"}
  2475  						},
  2476  					},
  2477  				},
  2478  			},
  2479  			expectedErr: "x509: a root or intermediate certificate is not authorized to sign for this name: DNS name \"beep.com\" is not permitted by any constraint",
  2480  		},
  2481  		{
  2482  			// A name constraint on the intermediate does not apply to the intermediate
  2483  			// itself, so this is a valid chain.
  2484  			name: "constrained intermediate, non-matching SAN",
  2485  			graph: trustGraphDescription{
  2486  				Roots: []rootDescription{{Subject: "root"}},
  2487  				Leaf:  "leaf",
  2488  				Graph: []trustGraphEdge{
  2489  					{
  2490  						Issuer:  "root",
  2491  						Subject: "inter",
  2492  						Type:    intermediateCertificate,
  2493  						MutateTemplate: func(t *Certificate) {
  2494  							t.DNSNames = []string{"beep.com"}
  2495  							t.PermittedDNSDomains = []string{"example.com"}
  2496  						},
  2497  					},
  2498  					{
  2499  						Issuer:  "inter",
  2500  						Subject: "leaf",
  2501  						Type:    leafCertificate,
  2502  						MutateTemplate: func(t *Certificate) {
  2503  							t.DNSNames = []string{"www.example.com"}
  2504  						},
  2505  					},
  2506  				},
  2507  			},
  2508  			expectedChains: []string{"CN=leaf -> CN=inter -> CN=root"},
  2509  		},
  2510  		{
  2511  			// A code constraint on the root, applying to one of two intermediates in the graph, should
  2512  			// result in only one valid chain.
  2513  			name: "code constrained root, two paths, one valid",
  2514  			graph: trustGraphDescription{
  2515  				Roots: []rootDescription{{Subject: "root", Constraint: func(chain []*Certificate) error {
  2516  					for _, c := range chain {
  2517  						if c.Subject.CommonName == "inter a" {
  2518  							return errors.New("bad")
  2519  						}
  2520  					}
  2521  					return nil
  2522  				}}},
  2523  				Leaf: "leaf",
  2524  				Graph: []trustGraphEdge{
  2525  					{
  2526  						Issuer:  "root",
  2527  						Subject: "inter a",
  2528  						Type:    intermediateCertificate,
  2529  					},
  2530  					{
  2531  						Issuer:  "root",
  2532  						Subject: "inter b",
  2533  						Type:    intermediateCertificate,
  2534  					},
  2535  					{
  2536  						Issuer:  "inter a",
  2537  						Subject: "inter c",
  2538  						Type:    intermediateCertificate,
  2539  					},
  2540  					{
  2541  						Issuer:  "inter b",
  2542  						Subject: "inter c",
  2543  						Type:    intermediateCertificate,
  2544  					},
  2545  					{
  2546  						Issuer:  "inter c",
  2547  						Subject: "leaf",
  2548  						Type:    leafCertificate,
  2549  					},
  2550  				},
  2551  			},
  2552  			expectedChains: []string{"CN=leaf -> CN=inter c -> CN=inter b -> CN=root"},
  2553  		},
  2554  		{
  2555  			// A code constraint on the root, applying to the only path, should result in an error.
  2556  			name: "code constrained root, one invalid path",
  2557  			graph: trustGraphDescription{
  2558  				Roots: []rootDescription{{Subject: "root", Constraint: func(chain []*Certificate) error {
  2559  					for _, c := range chain {
  2560  						if c.Subject.CommonName == "leaf" {
  2561  							return errors.New("bad")
  2562  						}
  2563  					}
  2564  					return nil
  2565  				}}},
  2566  				Leaf: "leaf",
  2567  				Graph: []trustGraphEdge{
  2568  					{
  2569  						Issuer:  "root",
  2570  						Subject: "inter",
  2571  						Type:    intermediateCertificate,
  2572  					},
  2573  					{
  2574  						Issuer:  "inter",
  2575  						Subject: "leaf",
  2576  						Type:    leafCertificate,
  2577  					},
  2578  				},
  2579  			},
  2580  			expectedErr: "x509: certificate signed by unknown authority (possibly because of \"bad\" while trying to verify candidate authority certificate \"root\")",
  2581  		},
  2582  	}
  2583  
  2584  	for _, tc := range tests {
  2585  		t.Run(tc.name, func(t *testing.T) {
  2586  			roots, intermediates, leaf := buildTrustGraph(t, tc.graph)
  2587  			chains, err := leaf.Verify(VerifyOptions{
  2588  				Roots:         roots,
  2589  				Intermediates: intermediates,
  2590  			})
  2591  			if err != nil && err.Error() != tc.expectedErr {
  2592  				t.Fatalf("unexpected error: got %q, want %q", err, tc.expectedErr)
  2593  			}
  2594  			if len(tc.expectedChains) == 0 {
  2595  				return
  2596  			}
  2597  			gotChains := chainsToStrings(chains)
  2598  			if !reflect.DeepEqual(gotChains, tc.expectedChains) {
  2599  				t.Errorf("unexpected chains returned:\ngot:\n\t%s\nwant:\n\t%s", strings.Join(gotChains, "\n\t"), strings.Join(tc.expectedChains, "\n\t"))
  2600  			}
  2601  		})
  2602  	}
  2603  }
  2604  
  2605  func TestEKUEnforcement(t *testing.T) {
  2606  	type ekuDescs struct {
  2607  		EKUs    []ExtKeyUsage
  2608  		Unknown []asn1.ObjectIdentifier
  2609  	}
  2610  	tests := []struct {
  2611  		name       string
  2612  		root       ekuDescs
  2613  		inters     []ekuDescs
  2614  		leaf       ekuDescs
  2615  		verifyEKUs []ExtKeyUsage
  2616  		err        string
  2617  	}{
  2618  		{
  2619  			name:       "valid, full chain",
  2620  			root:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2621  			inters:     []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}}},
  2622  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2623  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2624  		},
  2625  		{
  2626  			name:       "valid, only leaf has EKU",
  2627  			root:       ekuDescs{},
  2628  			inters:     []ekuDescs{ekuDescs{}},
  2629  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2630  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2631  		},
  2632  		{
  2633  			name:       "invalid, serverAuth not nested",
  2634  			root:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
  2635  			inters:     []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
  2636  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
  2637  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2638  			err:        "x509: certificate specifies an incompatible key usage",
  2639  		},
  2640  		{
  2641  			name:       "valid, two EKUs, one path",
  2642  			root:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2643  			inters:     []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
  2644  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
  2645  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
  2646  		},
  2647  		{
  2648  			name: "invalid, ladder",
  2649  			root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2650  			inters: []ekuDescs{
  2651  				ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
  2652  				ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
  2653  				ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
  2654  				ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2655  			},
  2656  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2657  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
  2658  			err:        "x509: certificate specifies an incompatible key usage",
  2659  		},
  2660  		{
  2661  			name:       "valid, intermediate has no EKU",
  2662  			root:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2663  			inters:     []ekuDescs{ekuDescs{}},
  2664  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2665  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2666  		},
  2667  		{
  2668  			name:       "invalid, intermediate has no EKU and no nested path",
  2669  			root:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
  2670  			inters:     []ekuDescs{ekuDescs{}},
  2671  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2672  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
  2673  			err:        "x509: certificate specifies an incompatible key usage",
  2674  		},
  2675  		{
  2676  			name:       "invalid, intermediate has unknown EKU",
  2677  			root:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2678  			inters:     []ekuDescs{ekuDescs{Unknown: []asn1.ObjectIdentifier{{1, 2, 3}}}},
  2679  			leaf:       ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
  2680  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2681  			err:        "x509: certificate specifies an incompatible key usage",
  2682  		},
  2683  	}
  2684  
  2685  	k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2686  	if err != nil {
  2687  		t.Fatalf("failed to generate test key: %s", err)
  2688  	}
  2689  
  2690  	for _, tc := range tests {
  2691  		t.Run(tc.name, func(t *testing.T) {
  2692  			rootPool := NewCertPool()
  2693  			root := genCertEdge(t, "root", k, func(c *Certificate) {
  2694  				c.ExtKeyUsage = tc.root.EKUs
  2695  				c.UnknownExtKeyUsage = tc.root.Unknown
  2696  			}, rootCertificate, nil, k)
  2697  			rootPool.AddCert(root)
  2698  
  2699  			parent := root
  2700  			interPool := NewCertPool()
  2701  			for i, interEKUs := range tc.inters {
  2702  				inter := genCertEdge(t, fmt.Sprintf("inter %d", i), k, func(c *Certificate) {
  2703  					c.ExtKeyUsage = interEKUs.EKUs
  2704  					c.UnknownExtKeyUsage = interEKUs.Unknown
  2705  				}, intermediateCertificate, parent, k)
  2706  				interPool.AddCert(inter)
  2707  				parent = inter
  2708  			}
  2709  
  2710  			leaf := genCertEdge(t, "leaf", k, func(c *Certificate) {
  2711  				c.ExtKeyUsage = tc.leaf.EKUs
  2712  				c.UnknownExtKeyUsage = tc.leaf.Unknown
  2713  			}, intermediateCertificate, parent, k)
  2714  
  2715  			_, err := leaf.Verify(VerifyOptions{Roots: rootPool, Intermediates: interPool, KeyUsages: tc.verifyEKUs})
  2716  			if err == nil && tc.err != "" {
  2717  				t.Errorf("expected error")
  2718  			} else if err != nil && err.Error() != tc.err {
  2719  				t.Errorf("unexpected error: want %q, got %q", err.Error(), tc.err)
  2720  			}
  2721  		})
  2722  	}
  2723  }
  2724  
  2725  func TestVerifyEKURootAsLeaf(t *testing.T) {
  2726  	k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2727  	if err != nil {
  2728  		t.Fatalf("failed to generate key: %s", err)
  2729  	}
  2730  
  2731  	for _, tc := range []struct {
  2732  		rootEKUs   []ExtKeyUsage
  2733  		verifyEKUs []ExtKeyUsage
  2734  		succeed    bool
  2735  	}{
  2736  		{
  2737  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2738  			succeed:    true,
  2739  		},
  2740  		{
  2741  			rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2742  			succeed:  true,
  2743  		},
  2744  		{
  2745  			rootEKUs:   []ExtKeyUsage{ExtKeyUsageServerAuth},
  2746  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2747  			succeed:    true,
  2748  		},
  2749  		{
  2750  			rootEKUs:   []ExtKeyUsage{ExtKeyUsageServerAuth},
  2751  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageAny},
  2752  			succeed:    true,
  2753  		},
  2754  		{
  2755  			rootEKUs:   []ExtKeyUsage{ExtKeyUsageAny},
  2756  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2757  			succeed:    true,
  2758  		},
  2759  		{
  2760  			rootEKUs:   []ExtKeyUsage{ExtKeyUsageClientAuth},
  2761  			verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  2762  			succeed:    false,
  2763  		},
  2764  	} {
  2765  		t.Run(fmt.Sprintf("root EKUs %#v, verify EKUs %#v", tc.rootEKUs, tc.verifyEKUs), func(t *testing.T) {
  2766  			tmpl := &Certificate{
  2767  				SerialNumber: big.NewInt(1),
  2768  				Subject:      pkix.Name{CommonName: "root"},
  2769  				NotBefore:    time.Now().Add(-time.Hour),
  2770  				NotAfter:     time.Now().Add(time.Hour),
  2771  				DNSNames:     []string{"localhost"},
  2772  				ExtKeyUsage:  tc.rootEKUs,
  2773  			}
  2774  			rootDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
  2775  			if err != nil {
  2776  				t.Fatalf("failed to create certificate: %s", err)
  2777  			}
  2778  			root, err := ParseCertificate(rootDER)
  2779  			if err != nil {
  2780  				t.Fatalf("failed to parse certificate: %s", err)
  2781  			}
  2782  			roots := NewCertPool()
  2783  			roots.AddCert(root)
  2784  
  2785  			_, err = root.Verify(VerifyOptions{Roots: roots, KeyUsages: tc.verifyEKUs})
  2786  			if err == nil && !tc.succeed {
  2787  				t.Error("verification succeed")
  2788  			} else if err != nil && tc.succeed {
  2789  				t.Errorf("verification failed: %q", err)
  2790  			}
  2791  		})
  2792  	}
  2793  
  2794  }
  2795  
  2796  func TestVerifyNilPubKey(t *testing.T) {
  2797  	c := &Certificate{
  2798  		RawIssuer:      []byte{1, 2, 3},
  2799  		AuthorityKeyId: []byte{1, 2, 3},
  2800  	}
  2801  	opts := &VerifyOptions{}
  2802  	opts.Roots = NewCertPool()
  2803  	r := &Certificate{
  2804  		RawSubject:   []byte{1, 2, 3},
  2805  		SubjectKeyId: []byte{1, 2, 3},
  2806  	}
  2807  	opts.Roots.AddCert(r)
  2808  
  2809  	_, err := c.buildChains([]*Certificate{r}, nil, opts)
  2810  	if _, ok := err.(UnknownAuthorityError); !ok {
  2811  		t.Fatalf("buildChains returned unexpected error, got: %v, want %v", err, UnknownAuthorityError{})
  2812  	}
  2813  }
  2814  
  2815  func TestVerifyBareWildcard(t *testing.T) {
  2816  	k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2817  	if err != nil {
  2818  		t.Fatalf("failed to generate key: %s", err)
  2819  	}
  2820  	tmpl := &Certificate{
  2821  		SerialNumber: big.NewInt(1),
  2822  		Subject:      pkix.Name{CommonName: "test"},
  2823  		NotBefore:    time.Now().Add(-time.Hour),
  2824  		NotAfter:     time.Now().Add(time.Hour),
  2825  		DNSNames:     []string{"*"},
  2826  	}
  2827  	cDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
  2828  	if err != nil {
  2829  		t.Fatalf("failed to create certificate: %s", err)
  2830  	}
  2831  	c, err := ParseCertificate(cDER)
  2832  	if err != nil {
  2833  		t.Fatalf("failed to parse certificate: %s", err)
  2834  	}
  2835  
  2836  	if err := c.VerifyHostname("label"); err == nil {
  2837  		t.Fatalf("VerifyHostname unexpected success with bare wildcard SAN")
  2838  	}
  2839  }
  2840  

View as plain text