Source file src/crypto/x509/verify_test.go

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

View as plain text