github.com/emmansun/gmsm@v0.29.1/smx509/verify_test.go (about)

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