Source file src/crypto/x509/name_constraints_test.go

     1  // Copyright 2017 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  	"bytes"
     9  	"crypto/ecdsa"
    10  	"crypto/elliptic"
    11  	"crypto/rand"
    12  	"crypto/x509/pkix"
    13  	"encoding/asn1"
    14  	"encoding/hex"
    15  	"encoding/pem"
    16  	"fmt"
    17  	"internal/testenv"
    18  	"math/big"
    19  	"net"
    20  	"net/url"
    21  	"os"
    22  	"os/exec"
    23  	"strconv"
    24  	"strings"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  )
    29  
    30  const (
    31  	// testNameConstraintsAgainstOpenSSL can be set to true to run tests
    32  	// against the system OpenSSL. This is disabled by default because Go
    33  	// cannot depend on having OpenSSL installed at testing time.
    34  	testNameConstraintsAgainstOpenSSL = false
    35  
    36  	// debugOpenSSLFailure can be set to true, when
    37  	// testNameConstraintsAgainstOpenSSL is also true, to cause
    38  	// intermediate files to be preserved for debugging.
    39  	debugOpenSSLFailure = false
    40  )
    41  
    42  type nameConstraintsTest struct {
    43  	name          string
    44  	roots         []constraintsSpec
    45  	intermediates [][]constraintsSpec
    46  	leaf          leafSpec
    47  	requestedEKUs []ExtKeyUsage
    48  	expectedError string
    49  	noOpenSSL     bool
    50  	ignoreCN      bool
    51  }
    52  
    53  type constraintsSpec struct {
    54  	ok   []string
    55  	bad  []string
    56  	ekus []string
    57  }
    58  
    59  type leafSpec struct {
    60  	sans []string
    61  	ekus []string
    62  	cn   string
    63  }
    64  
    65  var nameConstraintsTests = []nameConstraintsTest{
    66  	{
    67  		name:  "certificate generation process",
    68  		roots: make([]constraintsSpec, 1),
    69  		leaf: leafSpec{
    70  			sans: []string{"dns:example.com"},
    71  		},
    72  	},
    73  	{
    74  		name:  "single level of intermediate",
    75  		roots: make([]constraintsSpec, 1),
    76  		intermediates: [][]constraintsSpec{
    77  			{
    78  				{},
    79  			},
    80  		},
    81  		leaf: leafSpec{
    82  			sans: []string{"dns:example.com"},
    83  		},
    84  	},
    85  	{
    86  		name:  "two levels of intermediates",
    87  		roots: make([]constraintsSpec, 1),
    88  		intermediates: [][]constraintsSpec{
    89  			{
    90  				{},
    91  			},
    92  			{
    93  				{},
    94  			},
    95  		},
    96  		leaf: leafSpec{
    97  			sans: []string{"dns:example.com"},
    98  		},
    99  	},
   100  	{
   101  		name: "matching DNS constraint in root",
   102  		roots: []constraintsSpec{
   103  			{
   104  				ok: []string{"dns:example.com"},
   105  			},
   106  		},
   107  		intermediates: [][]constraintsSpec{
   108  			{
   109  				{},
   110  			},
   111  		},
   112  		leaf: leafSpec{
   113  			sans: []string{"dns:example.com"},
   114  		},
   115  	},
   116  	{
   117  		name:  "matching DNS constraint in intermediate",
   118  		roots: make([]constraintsSpec, 1),
   119  		intermediates: [][]constraintsSpec{
   120  			{
   121  				{
   122  					ok: []string{"dns:example.com"},
   123  				},
   124  			},
   125  		},
   126  		leaf: leafSpec{
   127  			sans: []string{"dns:example.com"},
   128  		},
   129  	},
   130  	{
   131  		name: "leading period only matches subdomains",
   132  		roots: []constraintsSpec{
   133  			{
   134  				ok: []string{"dns:.example.com"},
   135  			},
   136  		},
   137  		intermediates: [][]constraintsSpec{
   138  			{
   139  				{},
   140  			},
   141  		},
   142  		leaf: leafSpec{
   143  			sans: []string{"dns:example.com"},
   144  		},
   145  		expectedError: "\"example.com\" is not permitted",
   146  	},
   147  	{
   148  		name:  "leading period matches subdomains",
   149  		roots: make([]constraintsSpec, 1),
   150  		intermediates: [][]constraintsSpec{
   151  			{
   152  				{
   153  					ok: []string{"dns:.example.com"},
   154  				},
   155  			},
   156  		},
   157  		leaf: leafSpec{
   158  			sans: []string{"dns:foo.example.com"},
   159  		},
   160  	},
   161  	{
   162  		name: "leading period matches multiple levels of subdomains",
   163  		roots: []constraintsSpec{
   164  			{
   165  				ok: []string{"dns:.example.com"},
   166  			},
   167  		},
   168  		intermediates: [][]constraintsSpec{
   169  			{
   170  				{},
   171  			},
   172  		},
   173  		leaf: leafSpec{
   174  			sans: []string{"dns:foo.bar.example.com"},
   175  		},
   176  	},
   177  	{
   178  		name: "specifying a permitted list of names does not exclude other name types",
   179  		roots: []constraintsSpec{
   180  			{
   181  				ok: []string{"dns:.example.com"},
   182  			},
   183  		},
   184  		intermediates: [][]constraintsSpec{
   185  			{
   186  				{},
   187  			},
   188  		},
   189  		leaf: leafSpec{
   190  			sans: []string{"ip:10.1.1.1"},
   191  		},
   192  	},
   193  	{
   194  		name: "specifying a permitted list of names does not exclude other name types",
   195  		roots: []constraintsSpec{
   196  			{
   197  				ok: []string{"ip:10.0.0.0/8"},
   198  			},
   199  		},
   200  		intermediates: [][]constraintsSpec{
   201  			{
   202  				{},
   203  			},
   204  		},
   205  		leaf: leafSpec{
   206  			sans: []string{"dns:example.com"},
   207  		},
   208  	},
   209  	{
   210  		name: "intermediates can try to permit other names, which isn't forbidden if the leaf doesn't mention them",
   211  		roots: []constraintsSpec{
   212  			{
   213  				ok: []string{"dns:example.com"},
   214  			},
   215  		},
   216  		intermediates: [][]constraintsSpec{
   217  			{
   218  				{
   219  					ok: []string{"dns:example.com", "dns:foo.com"},
   220  				},
   221  			},
   222  		},
   223  		leaf: leafSpec{
   224  			sans: []string{"dns:example.com"},
   225  		},
   226  	},
   227  	{
   228  		name: "intermediates cannot add permitted names that the root doesn't grant them",
   229  		roots: []constraintsSpec{
   230  			{
   231  				ok: []string{"dns:example.com"},
   232  			},
   233  		},
   234  		intermediates: [][]constraintsSpec{
   235  			{
   236  				{
   237  					ok: []string{"dns:foo.example.com", "dns:foo.com"},
   238  				},
   239  			},
   240  		},
   241  		leaf: leafSpec{
   242  			sans: []string{"dns:foo.com"},
   243  		},
   244  		expectedError: "\"foo.com\" is not permitted",
   245  	},
   246  	{
   247  		name: "intermediates can further limit their scope if they wish",
   248  		roots: []constraintsSpec{
   249  			{
   250  				ok: []string{"dns:.example.com"},
   251  			},
   252  		},
   253  		intermediates: [][]constraintsSpec{
   254  			{
   255  				{
   256  					ok: []string{"dns:.bar.example.com"},
   257  				},
   258  			},
   259  		},
   260  		leaf: leafSpec{
   261  			sans: []string{"dns:foo.bar.example.com"},
   262  		},
   263  	},
   264  	{
   265  		name: "intermediates can further limit their scope and that limitation is effective",
   266  		roots: []constraintsSpec{
   267  			{
   268  				ok: []string{"dns:.example.com"},
   269  			},
   270  		},
   271  		intermediates: [][]constraintsSpec{
   272  			{
   273  				{
   274  					ok: []string{"dns:.bar.example.com"},
   275  				},
   276  			},
   277  		},
   278  		leaf: leafSpec{
   279  			sans: []string{"dns:foo.notbar.example.com"},
   280  		},
   281  		expectedError: "\"foo.notbar.example.com\" is not permitted",
   282  	},
   283  	{
   284  		name: "roots can exclude subtrees and that doesn't affect other names",
   285  		roots: []constraintsSpec{
   286  			{
   287  				bad: []string{"dns:.example.com"},
   288  			},
   289  		},
   290  		intermediates: [][]constraintsSpec{
   291  			{
   292  				{},
   293  			},
   294  		},
   295  		leaf: leafSpec{
   296  			sans: []string{"dns:foo.com"},
   297  		},
   298  	},
   299  	{
   300  		name: "roots exclusions are effective",
   301  		roots: []constraintsSpec{
   302  			{
   303  				bad: []string{"dns:.example.com"},
   304  			},
   305  		},
   306  		intermediates: [][]constraintsSpec{
   307  			{
   308  				{},
   309  			},
   310  		},
   311  		leaf: leafSpec{
   312  			sans: []string{"dns:foo.example.com"},
   313  		},
   314  		expectedError: "\"foo.example.com\" is excluded",
   315  	},
   316  	{
   317  		name:  "intermediates can also exclude names and that doesn't affect other names",
   318  		roots: make([]constraintsSpec, 1),
   319  		intermediates: [][]constraintsSpec{
   320  			{
   321  				{
   322  					bad: []string{"dns:.example.com"},
   323  				},
   324  			},
   325  		},
   326  		leaf: leafSpec{
   327  			sans: []string{"dns:foo.com"},
   328  		},
   329  	},
   330  	{
   331  		name:  "intermediate exclusions are effective",
   332  		roots: make([]constraintsSpec, 1),
   333  		intermediates: [][]constraintsSpec{
   334  			{
   335  				{
   336  					bad: []string{"dns:.example.com"},
   337  				},
   338  			},
   339  		},
   340  		leaf: leafSpec{
   341  			sans: []string{"dns:foo.example.com"},
   342  		},
   343  		expectedError: "\"foo.example.com\" is excluded",
   344  	},
   345  	{
   346  		name: "having an exclusion doesn't prohibit other types of names",
   347  		roots: []constraintsSpec{
   348  			{
   349  				bad: []string{"dns:.example.com"},
   350  			},
   351  		},
   352  		intermediates: [][]constraintsSpec{
   353  			{
   354  				{},
   355  			},
   356  		},
   357  		leaf: leafSpec{
   358  			sans: []string{"dns:foo.com", "ip:10.1.1.1"},
   359  		},
   360  	},
   361  	{
   362  		name: "IP-based exclusions are permitted and don't affect unrelated IP addresses",
   363  		roots: []constraintsSpec{
   364  			{
   365  				bad: []string{"ip:10.0.0.0/8"},
   366  			},
   367  		},
   368  		intermediates: [][]constraintsSpec{
   369  			{
   370  				{},
   371  			},
   372  		},
   373  		leaf: leafSpec{
   374  			sans: []string{"ip:192.168.1.1"},
   375  		},
   376  	},
   377  	{
   378  		name: "IP-based exclusions are effective",
   379  		roots: []constraintsSpec{
   380  			{
   381  				bad: []string{"ip:10.0.0.0/8"},
   382  			},
   383  		},
   384  		intermediates: [][]constraintsSpec{
   385  			{
   386  				{},
   387  			},
   388  		},
   389  		leaf: leafSpec{
   390  			sans: []string{"ip:10.0.0.1"},
   391  		},
   392  		expectedError: "\"10.0.0.1\" is excluded",
   393  	},
   394  	{
   395  		name: "intermediates can further constrain IP ranges",
   396  		roots: []constraintsSpec{
   397  			{
   398  				bad: []string{"ip:0.0.0.0/1"},
   399  			},
   400  		},
   401  		intermediates: [][]constraintsSpec{
   402  			{
   403  				{
   404  					bad: []string{"ip:11.0.0.0/8"},
   405  				},
   406  			},
   407  		},
   408  		leaf: leafSpec{
   409  			sans: []string{"ip:11.0.0.1"},
   410  		},
   411  		expectedError: "\"11.0.0.1\" is excluded",
   412  	},
   413  	{
   414  		name:  "multiple intermediates with incompatible constraints",
   415  		roots: make([]constraintsSpec, 1),
   416  		intermediates: [][]constraintsSpec{
   417  			{
   418  				{
   419  					ok: []string{"dns:.foo.com"},
   420  				},
   421  				{
   422  					ok: []string{"dns:.example.com"},
   423  				},
   424  			},
   425  		},
   426  		leaf: leafSpec{
   427  			sans: []string{"dns:foo.example.com"},
   428  		},
   429  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   430  	},
   431  	{
   432  		name:  "multiple intermediates with incompatible constraints swapped",
   433  		roots: make([]constraintsSpec, 1),
   434  		intermediates: [][]constraintsSpec{
   435  			{
   436  				{
   437  					ok: []string{"dns:.example.com"},
   438  				},
   439  				{
   440  					ok: []string{"dns:.foo.com"},
   441  				},
   442  			},
   443  		},
   444  		leaf: leafSpec{
   445  			sans: []string{"dns:foo.example.com"},
   446  		},
   447  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   448  	},
   449  	{
   450  		name: "multiple roots with incompatible constraints",
   451  		roots: []constraintsSpec{
   452  			{},
   453  			{
   454  				ok: []string{"dns:foo.com"},
   455  			},
   456  		},
   457  		intermediates: [][]constraintsSpec{
   458  			{
   459  				{},
   460  			},
   461  		},
   462  		leaf: leafSpec{
   463  			sans: []string{"dns:example.com"},
   464  		},
   465  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   466  	},
   467  	{
   468  		name: "multiple roots with incompatible constraints swapped",
   469  		roots: []constraintsSpec{
   470  			{
   471  				ok: []string{"dns:foo.com"},
   472  			},
   473  			{},
   474  		},
   475  		intermediates: [][]constraintsSpec{
   476  			{
   477  				{},
   478  			},
   479  		},
   480  		leaf: leafSpec{
   481  			sans: []string{"dns:example.com"},
   482  		},
   483  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   484  	},
   485  	{
   486  		name: "chain building with multiple intermediates and roots",
   487  		roots: []constraintsSpec{
   488  			{
   489  				ok: []string{"dns:foo.com"},
   490  			},
   491  			{
   492  				ok: []string{"dns:example.com"},
   493  			},
   494  			{},
   495  		},
   496  		intermediates: [][]constraintsSpec{
   497  			{
   498  				{},
   499  				{
   500  					ok: []string{"dns:foo.com"},
   501  				},
   502  			},
   503  			{
   504  				{},
   505  				{
   506  					ok: []string{"dns:foo.com"},
   507  				},
   508  			},
   509  		},
   510  		leaf: leafSpec{
   511  			sans: []string{"dns:bar.com"},
   512  		},
   513  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   514  	},
   515  	{
   516  		name: "chain building fails with no valid path",
   517  		roots: []constraintsSpec{
   518  			{
   519  				ok: []string{"dns:foo.com"},
   520  			},
   521  			{
   522  				ok: []string{"dns:example.com"},
   523  			},
   524  		},
   525  		intermediates: [][]constraintsSpec{
   526  			{
   527  				{},
   528  				{
   529  					ok: []string{"dns:foo.com"},
   530  				},
   531  			},
   532  			{
   533  				{
   534  					ok: []string{"dns:bar.com"},
   535  				},
   536  				{
   537  					ok: []string{"dns:foo.com"},
   538  				},
   539  			},
   540  		},
   541  		leaf: leafSpec{
   542  			sans: []string{"dns:bar.com"},
   543  		},
   544  		expectedError: "\"bar.com\" is not permitted",
   545  	},
   546  	{
   547  		name:  "unknown name types are unconstrained",
   548  		roots: make([]constraintsSpec, 1),
   549  		intermediates: [][]constraintsSpec{
   550  			{
   551  				{},
   552  			},
   553  		},
   554  		leaf: leafSpec{
   555  			sans: []string{"unknown:"},
   556  		},
   557  	},
   558  	{
   559  		name: "unknown name types allowed in constrained chain",
   560  		roots: []constraintsSpec{
   561  			{
   562  				ok: []string{"dns:foo.com", "dns:.foo.com"},
   563  			},
   564  		},
   565  		intermediates: [][]constraintsSpec{
   566  			{
   567  				{},
   568  			},
   569  		},
   570  		leaf: leafSpec{
   571  			sans: []string{"unknown:"},
   572  		},
   573  	},
   574  	{
   575  		name: "CN is ignored in constrained chain",
   576  		roots: []constraintsSpec{
   577  			{
   578  				ok: []string{"dns:foo.com", "dns:.foo.com"},
   579  			},
   580  		},
   581  		intermediates: [][]constraintsSpec{
   582  			{
   583  				{},
   584  			},
   585  		},
   586  		leaf: leafSpec{
   587  			sans: []string{},
   588  			cn:   "foo.com",
   589  		},
   590  	},
   591  	{
   592  		name: "IPv6 permitted constraint",
   593  		roots: []constraintsSpec{
   594  			{
   595  				ok: []string{"ip:2000:abcd::/32"},
   596  			},
   597  		},
   598  		intermediates: [][]constraintsSpec{
   599  			{
   600  				{},
   601  			},
   602  		},
   603  		leaf: leafSpec{
   604  			sans: []string{"ip:2000:abcd:1234::"},
   605  		},
   606  	},
   607  	{
   608  		name: "IPv6 permitted constraint is effective",
   609  		roots: []constraintsSpec{
   610  			{
   611  				ok: []string{"ip:2000:abcd::/32"},
   612  			},
   613  		},
   614  		intermediates: [][]constraintsSpec{
   615  			{
   616  				{},
   617  			},
   618  		},
   619  		leaf: leafSpec{
   620  			sans: []string{"ip:2000:1234:abcd::"},
   621  		},
   622  		expectedError: "\"2000:1234:abcd::\" is not permitted",
   623  	},
   624  	{
   625  		name: "IPv6 permitted constraint does not affect DNS",
   626  		roots: []constraintsSpec{
   627  			{
   628  				ok: []string{"ip:2000:abcd::/32"},
   629  			},
   630  		},
   631  		intermediates: [][]constraintsSpec{
   632  			{
   633  				{},
   634  			},
   635  		},
   636  		leaf: leafSpec{
   637  			sans: []string{"ip:2000:abcd::", "dns:foo.com"},
   638  		},
   639  	},
   640  	{
   641  		name: "IPv6 excluded constraint",
   642  		roots: []constraintsSpec{
   643  			{
   644  				bad: []string{"ip:2000:abcd::/32"},
   645  			},
   646  		},
   647  		intermediates: [][]constraintsSpec{
   648  			{
   649  				{},
   650  			},
   651  		},
   652  		leaf: leafSpec{
   653  			sans: []string{"ip:2000:1234::"},
   654  		},
   655  	},
   656  	{
   657  		name: "IPv6 excluded constraint is effective",
   658  		roots: []constraintsSpec{
   659  			{
   660  				bad: []string{"ip:2000:abcd::/32"},
   661  			},
   662  		},
   663  		intermediates: [][]constraintsSpec{
   664  			{
   665  				{},
   666  			},
   667  		},
   668  		leaf: leafSpec{
   669  			sans: []string{"ip:2000:abcd::"},
   670  		},
   671  		expectedError: "\"2000:abcd::\" is excluded",
   672  	},
   673  	{
   674  		name: "IPv6 constraint does not permit IPv4",
   675  		roots: []constraintsSpec{
   676  			{
   677  				ok: []string{"ip:2000:abcd::/32"},
   678  			},
   679  		},
   680  		intermediates: [][]constraintsSpec{
   681  			{
   682  				{},
   683  			},
   684  		},
   685  		leaf: leafSpec{
   686  			sans: []string{"ip:10.0.0.1"},
   687  		},
   688  		expectedError: "\"10.0.0.1\" is not permitted",
   689  	},
   690  	{
   691  		name: "IPv4 constraint does not permit IPv6",
   692  		roots: []constraintsSpec{
   693  			{
   694  				ok: []string{"ip:10.0.0.0/8"},
   695  			},
   696  		},
   697  		intermediates: [][]constraintsSpec{
   698  			{
   699  				{},
   700  			},
   701  		},
   702  		leaf: leafSpec{
   703  			sans: []string{"ip:2000:abcd::"},
   704  		},
   705  		expectedError: "\"2000:abcd::\" is not permitted",
   706  	},
   707  	{
   708  		name: "unknown excluded constraint does not affect other names",
   709  		roots: []constraintsSpec{
   710  			{
   711  				bad: []string{"unknown:"},
   712  			},
   713  		},
   714  		intermediates: [][]constraintsSpec{
   715  			{
   716  				{},
   717  			},
   718  		},
   719  		leaf: leafSpec{
   720  			sans: []string{"dns:example.com"},
   721  		},
   722  	},
   723  	{
   724  		name: "unknown permitted constraint does not affect other names",
   725  		roots: []constraintsSpec{
   726  			{
   727  				ok: []string{"unknown:"},
   728  			},
   729  		},
   730  		intermediates: [][]constraintsSpec{
   731  			{
   732  				{},
   733  			},
   734  		},
   735  		leaf: leafSpec{
   736  			sans: []string{"dns:example.com"},
   737  		},
   738  	},
   739  	{
   740  		name: "exact email constraint",
   741  		roots: []constraintsSpec{
   742  			{
   743  				ok: []string{"email:foo@example.com"},
   744  			},
   745  		},
   746  		intermediates: [][]constraintsSpec{
   747  			{
   748  				{},
   749  			},
   750  		},
   751  		leaf: leafSpec{
   752  			sans: []string{"email:foo@example.com"},
   753  		},
   754  	},
   755  	{
   756  		name: "exact email constraint is effective",
   757  		roots: []constraintsSpec{
   758  			{
   759  				ok: []string{"email:foo@example.com"},
   760  			},
   761  		},
   762  		intermediates: [][]constraintsSpec{
   763  			{
   764  				{},
   765  			},
   766  		},
   767  		leaf: leafSpec{
   768  			sans: []string{"email:bar@example.com"},
   769  		},
   770  		expectedError: "\"bar@example.com\" is not permitted",
   771  	},
   772  	{
   773  		name: "email canonicalization",
   774  		roots: []constraintsSpec{
   775  			{
   776  				ok: []string{"email:foo@example.com"},
   777  			},
   778  		},
   779  		intermediates: [][]constraintsSpec{
   780  			{
   781  				{},
   782  			},
   783  		},
   784  		leaf: leafSpec{
   785  			sans: []string{"email:\"\\f\\o\\o\"@example.com"},
   786  		},
   787  		noOpenSSL: true, // OpenSSL doesn't canonicalise email addresses before matching
   788  	},
   789  	{
   790  		name: "email host constraint",
   791  		roots: []constraintsSpec{
   792  			{
   793  				ok: []string{"email:example.com"},
   794  			},
   795  		},
   796  		intermediates: [][]constraintsSpec{
   797  			{
   798  				{},
   799  			},
   800  		},
   801  		leaf: leafSpec{
   802  			sans: []string{"email:foo@example.com"},
   803  		},
   804  	},
   805  	{
   806  		name: "email host constraint does not match subdomains",
   807  		roots: []constraintsSpec{
   808  			{
   809  				ok: []string{"email:example.com"},
   810  			},
   811  		},
   812  		intermediates: [][]constraintsSpec{
   813  			{
   814  				{},
   815  			},
   816  		},
   817  		leaf: leafSpec{
   818  			sans: []string{"email:foo@sub.example.com"},
   819  		},
   820  		expectedError: "\"foo@sub.example.com\" is not permitted",
   821  	},
   822  	{
   823  		name: "excluded email host constraint",
   824  		roots: []constraintsSpec{
   825  			{
   826  				bad: []string{"email:example.com"},
   827  			},
   828  		},
   829  		intermediates: [][]constraintsSpec{
   830  			{
   831  				{},
   832  			},
   833  		},
   834  		leaf: leafSpec{
   835  			sans: []string{"email:foo@example.com"},
   836  		},
   837  		expectedError: "\"foo@example.com\" is excluded",
   838  	},
   839  	{
   840  		name: "excluded email host constraint does not match subdomains",
   841  		roots: []constraintsSpec{
   842  			{
   843  				bad: []string{"email:example.com"},
   844  			},
   845  		},
   846  		intermediates: [][]constraintsSpec{
   847  			{
   848  				{},
   849  			},
   850  		},
   851  		leaf: leafSpec{
   852  			sans: []string{"email:foo@sub.example.com"},
   853  		},
   854  	},
   855  	{
   856  		name: "excluded email subdomain constraint does not match parent",
   857  		roots: []constraintsSpec{
   858  			{
   859  				bad: []string{"email:.example.com"},
   860  			},
   861  		},
   862  		intermediates: [][]constraintsSpec{
   863  			{
   864  				{},
   865  			},
   866  		},
   867  		leaf: leafSpec{
   868  			sans: []string{"email:foo@example.com"},
   869  		},
   870  	},
   871  	{
   872  		name: "excluded email host constraint treats wildcard literally",
   873  		roots: []constraintsSpec{
   874  			{
   875  				bad: []string{"email:example.com"},
   876  			},
   877  		},
   878  		intermediates: [][]constraintsSpec{
   879  			{
   880  				{},
   881  			},
   882  		},
   883  		leaf: leafSpec{
   884  			sans: []string{"email:foo@*.example.com"},
   885  		},
   886  		noOpenSSL: true, // OpenSSL rejects wildcard rfc822Name domains.
   887  	},
   888  	{
   889  		name: "email host and subdomain constraints",
   890  		roots: []constraintsSpec{
   891  			{
   892  				// Mixed case exercises case-insensitive sorting and matching.
   893  				ok: []string{"email:EXAMPLE.com", "email:.EXAMPLE.com"},
   894  			},
   895  		},
   896  		intermediates: [][]constraintsSpec{
   897  			{
   898  				{},
   899  			},
   900  		},
   901  		leaf: leafSpec{
   902  			sans: []string{
   903  				"email:foo@example.com",
   904  				"email:foo@sub.example.com",
   905  			},
   906  		},
   907  	},
   908  	{
   909  		name: "email subdomain constraint prunes covered host",
   910  		roots: []constraintsSpec{
   911  			{
   912  				// Mixed case exercises case-insensitive pruning and matching.
   913  				ok: []string{"email:.EXAMPLE.com", "email:sub.example.com"},
   914  			},
   915  		},
   916  		intermediates: [][]constraintsSpec{
   917  			{
   918  				{},
   919  			},
   920  		},
   921  		leaf: leafSpec{
   922  			sans: []string{
   923  				"email:foo@sub.example.com",
   924  				"email:foo@deep.sub.example.com",
   925  			},
   926  		},
   927  	},
   928  	{
   929  		name: "email subdomain constraint",
   930  		roots: []constraintsSpec{
   931  			{
   932  				ok: []string{"email:.example.com"},
   933  			},
   934  		},
   935  		intermediates: [][]constraintsSpec{
   936  			{
   937  				{},
   938  			},
   939  		},
   940  		leaf: leafSpec{
   941  			sans: []string{"email:foo@sub.example.com"},
   942  		},
   943  	},
   944  	{
   945  		name: "email subdomain constraint does not match parent",
   946  		roots: []constraintsSpec{
   947  			{
   948  				ok: []string{"email:.example.com"},
   949  			},
   950  		},
   951  		intermediates: [][]constraintsSpec{
   952  			{
   953  				{},
   954  			},
   955  		},
   956  		leaf: leafSpec{
   957  			sans: []string{"email:foo@example.com"},
   958  		},
   959  		expectedError: "\"foo@example.com\" is not permitted",
   960  	},
   961  	{
   962  		name: "email subdomain constraint matches deeper subdomains",
   963  		roots: []constraintsSpec{
   964  			{
   965  				ok: []string{"email:.example.com"},
   966  			},
   967  		},
   968  		intermediates: [][]constraintsSpec{
   969  			{
   970  				{},
   971  			},
   972  		},
   973  		leaf: leafSpec{
   974  			sans: []string{"email:foo@sub.sub.example.com"},
   975  		},
   976  	},
   977  	{
   978  		name: "email local part is case-sensitive",
   979  		roots: []constraintsSpec{
   980  			{
   981  				ok: []string{"email:foo@example.com"},
   982  			},
   983  		},
   984  		intermediates: [][]constraintsSpec{
   985  			{
   986  				{},
   987  			},
   988  		},
   989  		leaf: leafSpec{
   990  			sans: []string{"email:Foo@example.com"},
   991  		},
   992  		expectedError: "\"Foo@example.com\" is not permitted",
   993  	},
   994  	{
   995  		name: "email domain part is case-insensitive",
   996  		roots: []constraintsSpec{
   997  			{
   998  				ok: []string{"email:foo@EXAMPLE.com"},
   999  			},
  1000  		},
  1001  		intermediates: [][]constraintsSpec{
  1002  			{
  1003  				{},
  1004  			},
  1005  		},
  1006  		leaf: leafSpec{
  1007  			sans: []string{"email:foo@example.com"},
  1008  		},
  1009  	},
  1010  	{
  1011  		name: "DNS domain is case-insensitive",
  1012  		roots: []constraintsSpec{
  1013  			{
  1014  				ok: []string{"dns:EXAMPLE.com"},
  1015  			},
  1016  		},
  1017  		intermediates: [][]constraintsSpec{
  1018  			{
  1019  				{},
  1020  			},
  1021  		},
  1022  		leaf: leafSpec{
  1023  			sans: []string{"dns:example.com"},
  1024  		},
  1025  	},
  1026  	{
  1027  		name: "URI constraint covers host",
  1028  		roots: []constraintsSpec{
  1029  			{
  1030  				ok: []string{"uri:example.com"},
  1031  			},
  1032  		},
  1033  		intermediates: [][]constraintsSpec{
  1034  			{
  1035  				{},
  1036  			},
  1037  		},
  1038  		leaf: leafSpec{
  1039  			sans: []string{
  1040  				"uri:http://example.com/bar",
  1041  				"uri:http://example.com:8080/",
  1042  				"uri:https://example.com/wibble#bar",
  1043  			},
  1044  		},
  1045  	},
  1046  	{
  1047  		name: "URI host constraint does not match subdomains",
  1048  		roots: []constraintsSpec{
  1049  			{
  1050  				ok: []string{"uri:example.com"},
  1051  			},
  1052  		},
  1053  		intermediates: [][]constraintsSpec{
  1054  			{
  1055  				{},
  1056  			},
  1057  		},
  1058  		leaf: leafSpec{
  1059  			sans: []string{"uri:http://sub.example.com/"},
  1060  		},
  1061  		expectedError: "\"http://sub.example.com/\" is not permitted",
  1062  	},
  1063  	{
  1064  		name: "URI with IP is rejected",
  1065  		roots: []constraintsSpec{
  1066  			{
  1067  				ok: []string{"uri:example.com"},
  1068  			},
  1069  		},
  1070  		intermediates: [][]constraintsSpec{
  1071  			{
  1072  				{},
  1073  			},
  1074  		},
  1075  		leaf: leafSpec{
  1076  			sans: []string{"uri:http://1.2.3.4/"},
  1077  		},
  1078  		expectedError: "URI with IP",
  1079  	},
  1080  	{
  1081  		name: "URI with IP and port is rejected",
  1082  		roots: []constraintsSpec{
  1083  			{
  1084  				ok: []string{"uri:example.com"},
  1085  			},
  1086  		},
  1087  		intermediates: [][]constraintsSpec{
  1088  			{
  1089  				{},
  1090  			},
  1091  		},
  1092  		leaf: leafSpec{
  1093  			sans: []string{"uri:http://1.2.3.4:43/"},
  1094  		},
  1095  		expectedError: "URI with IP",
  1096  	},
  1097  	{
  1098  		name: "URI with IPv6 is rejected",
  1099  		roots: []constraintsSpec{
  1100  			{
  1101  				ok: []string{"uri:example.com"},
  1102  			},
  1103  		},
  1104  		intermediates: [][]constraintsSpec{
  1105  			{
  1106  				{},
  1107  			},
  1108  		},
  1109  		leaf: leafSpec{
  1110  			sans: []string{"uri:http://[2006:abcd::1]/"},
  1111  		},
  1112  		expectedError: "URI with IP",
  1113  	},
  1114  	{
  1115  		name: "URI with IPv6 and port is rejected",
  1116  		roots: []constraintsSpec{
  1117  			{
  1118  				ok: []string{"uri:example.com"},
  1119  			},
  1120  		},
  1121  		intermediates: [][]constraintsSpec{
  1122  			{
  1123  				{},
  1124  			},
  1125  		},
  1126  		leaf: leafSpec{
  1127  			sans: []string{"uri:http://[2006:abcd::1]:16/"},
  1128  		},
  1129  		expectedError: "URI with IP",
  1130  	},
  1131  	{
  1132  		name: "URI permitted constraint is effective",
  1133  		roots: []constraintsSpec{
  1134  			{
  1135  				ok: []string{"uri:example.com"},
  1136  			},
  1137  		},
  1138  		intermediates: [][]constraintsSpec{
  1139  			{
  1140  				{},
  1141  			},
  1142  		},
  1143  		leaf: leafSpec{
  1144  			sans: []string{"uri:http://bar.com/"},
  1145  		},
  1146  		expectedError: "\"http://bar.com/\" is not permitted",
  1147  	},
  1148  	{
  1149  		name: "URI excluded constraint is effective",
  1150  		roots: []constraintsSpec{
  1151  			{
  1152  				bad: []string{"uri:foo.com"},
  1153  			},
  1154  		},
  1155  		intermediates: [][]constraintsSpec{
  1156  			{
  1157  				{},
  1158  			},
  1159  		},
  1160  		leaf: leafSpec{
  1161  			sans: []string{"uri:http://foo.com/"},
  1162  		},
  1163  		expectedError: "\"http://foo.com/\" is excluded",
  1164  	},
  1165  	{
  1166  		name: "excluded URI host constraint does not match subdomains",
  1167  		roots: []constraintsSpec{
  1168  			{
  1169  				bad: []string{"uri:foo.com"},
  1170  			},
  1171  		},
  1172  		intermediates: [][]constraintsSpec{
  1173  			{
  1174  				{},
  1175  			},
  1176  		},
  1177  		leaf: leafSpec{
  1178  			sans: []string{"uri:http://sub.foo.com/"},
  1179  		},
  1180  	},
  1181  	{
  1182  		name: "excluded URI subdomain constraint does not match parent",
  1183  		roots: []constraintsSpec{
  1184  			{
  1185  				bad: []string{"uri:.example.com"},
  1186  			},
  1187  		},
  1188  		intermediates: [][]constraintsSpec{
  1189  			{
  1190  				{},
  1191  			},
  1192  		},
  1193  		leaf: leafSpec{
  1194  			sans: []string{"uri:https://example.com/"},
  1195  		},
  1196  	},
  1197  	{
  1198  		name: "excluded URI host constraint treats wildcard literally",
  1199  		roots: []constraintsSpec{
  1200  			{
  1201  				bad: []string{"uri:example.com"},
  1202  			},
  1203  		},
  1204  		intermediates: [][]constraintsSpec{
  1205  			{
  1206  				{},
  1207  			},
  1208  		},
  1209  		leaf: leafSpec{
  1210  			sans: []string{"uri:https://*.example.com/"},
  1211  		},
  1212  		noOpenSSL: true, // OpenSSL rejects wildcard URI hosts.
  1213  	},
  1214  	{
  1215  		name: "URI host and subdomain constraints",
  1216  		roots: []constraintsSpec{
  1217  			{
  1218  				// Mixed case exercises case-insensitive sorting and matching.
  1219  				ok: []string{"uri:EXAMPLE.com", "uri:.EXAMPLE.com"},
  1220  			},
  1221  		},
  1222  		intermediates: [][]constraintsSpec{
  1223  			{
  1224  				{},
  1225  			},
  1226  		},
  1227  		leaf: leafSpec{
  1228  			sans: []string{
  1229  				"uri:https://example.com/",
  1230  				"uri:https://sub.example.com/",
  1231  			},
  1232  		},
  1233  	},
  1234  	{
  1235  		name: "URI subdomain constraint",
  1236  		roots: []constraintsSpec{
  1237  			{
  1238  				ok: []string{"uri:.foo.com"},
  1239  			},
  1240  		},
  1241  		intermediates: [][]constraintsSpec{
  1242  			{
  1243  				{},
  1244  			},
  1245  		},
  1246  		leaf: leafSpec{
  1247  			sans: []string{"uri:http://www.foo.com/"},
  1248  		},
  1249  	},
  1250  	{
  1251  		name: "URI subdomain constraint does not match parent",
  1252  		roots: []constraintsSpec{
  1253  			{
  1254  				ok: []string{"uri:.foo.com"},
  1255  			},
  1256  		},
  1257  		intermediates: [][]constraintsSpec{
  1258  			{
  1259  				{},
  1260  			},
  1261  		},
  1262  		leaf: leafSpec{
  1263  			sans: []string{"uri:http://foo.com/"},
  1264  		},
  1265  		expectedError: "\"http://foo.com/\" is not permitted",
  1266  	},
  1267  	{
  1268  		name: "URI subdomain constraint matches deeper subdomains",
  1269  		roots: []constraintsSpec{
  1270  			{
  1271  				ok: []string{"uri:.foo.com"},
  1272  			},
  1273  		},
  1274  		intermediates: [][]constraintsSpec{
  1275  			{
  1276  				{},
  1277  			},
  1278  		},
  1279  		leaf: leafSpec{
  1280  			sans: []string{"uri:http://one.two.foo.com/"},
  1281  		},
  1282  	},
  1283  	{
  1284  		name: "URI constraint not matched by URN",
  1285  		roots: []constraintsSpec{
  1286  			{
  1287  				ok: []string{"uri:example.com"},
  1288  			},
  1289  		},
  1290  		intermediates: [][]constraintsSpec{
  1291  			{
  1292  				{},
  1293  			},
  1294  		},
  1295  		leaf: leafSpec{
  1296  			sans: []string{"uri:urn:example"},
  1297  		},
  1298  		expectedError: "URI with empty host",
  1299  	},
  1300  	{
  1301  		name: "IPv6 exclusion does not exclude all IPv4",
  1302  		roots: []constraintsSpec{
  1303  			{
  1304  				ok:  []string{"ip:1.2.3.0/24"},
  1305  				bad: []string{"ip:::0/0"},
  1306  			},
  1307  		},
  1308  		intermediates: [][]constraintsSpec{
  1309  			{
  1310  				{},
  1311  			},
  1312  		},
  1313  		leaf: leafSpec{
  1314  			sans: []string{"ip:1.2.3.4"},
  1315  		},
  1316  	},
  1317  	{
  1318  		name:  "empty EKU in CA means any is ok",
  1319  		roots: make([]constraintsSpec, 1),
  1320  		intermediates: [][]constraintsSpec{
  1321  			{
  1322  				{},
  1323  			},
  1324  		},
  1325  		leaf: leafSpec{
  1326  			sans: []string{"dns:example.com"},
  1327  			ekus: []string{"serverAuth", "other"},
  1328  		},
  1329  	},
  1330  	{
  1331  		name:  "any EKU means any is ok",
  1332  		roots: make([]constraintsSpec, 1),
  1333  		intermediates: [][]constraintsSpec{
  1334  			{
  1335  				{
  1336  					ekus: []string{"any"},
  1337  				},
  1338  			},
  1339  		},
  1340  		leaf: leafSpec{
  1341  			sans: []string{"dns:example.com"},
  1342  			ekus: []string{"serverAuth", "other"},
  1343  		},
  1344  	},
  1345  	// default.)
  1346  	{
  1347  		name:  "intermediate with enumerated EKUs",
  1348  		roots: make([]constraintsSpec, 1),
  1349  		intermediates: [][]constraintsSpec{
  1350  			{
  1351  				{
  1352  					ekus: []string{"email"},
  1353  				},
  1354  			},
  1355  		},
  1356  		leaf: leafSpec{
  1357  			sans: []string{"dns:example.com"},
  1358  			ekus: []string{"serverAuth"},
  1359  		},
  1360  		expectedError: "incompatible key usage",
  1361  	},
  1362  	{
  1363  		name:  "unknown EKU in leaf",
  1364  		roots: make([]constraintsSpec, 1),
  1365  		intermediates: [][]constraintsSpec{
  1366  			{
  1367  				{
  1368  					ekus: []string{"email"},
  1369  				},
  1370  			},
  1371  		},
  1372  		leaf: leafSpec{
  1373  			sans: []string{"dns:example.com"},
  1374  			ekus: []string{"other"},
  1375  		},
  1376  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
  1377  	},
  1378  	// certificate doesn't use them.
  1379  	{
  1380  		name: "intermediate cannot add EKUs not in root if leaf uses them",
  1381  		roots: []constraintsSpec{
  1382  			{
  1383  				ekus: []string{"serverAuth"},
  1384  			},
  1385  		},
  1386  		intermediates: [][]constraintsSpec{
  1387  			{
  1388  				{
  1389  					ekus: []string{"serverAuth", "email"},
  1390  				},
  1391  			},
  1392  		},
  1393  		leaf: leafSpec{
  1394  			sans: []string{"dns:example.com"},
  1395  			ekus: []string{"serverAuth"},
  1396  		},
  1397  	},
  1398  	{
  1399  		name: "EKUs in root are effective",
  1400  		roots: []constraintsSpec{
  1401  			{
  1402  				ekus: []string{"email"},
  1403  			},
  1404  		},
  1405  		intermediates: [][]constraintsSpec{
  1406  			{
  1407  				{
  1408  					ekus: []string{"serverAuth"},
  1409  				},
  1410  			},
  1411  		},
  1412  		leaf: leafSpec{
  1413  			sans: []string{"dns:example.com"},
  1414  			ekus: []string{"serverAuth"},
  1415  		},
  1416  		expectedError: "incompatible key usage",
  1417  	},
  1418  	{
  1419  		name: "netscapeSGC EKU does not permit server/client auth",
  1420  		roots: []constraintsSpec{
  1421  			{},
  1422  		},
  1423  		intermediates: [][]constraintsSpec{
  1424  			{
  1425  				{
  1426  					ekus: []string{"netscapeSGC"},
  1427  				},
  1428  			},
  1429  		},
  1430  		leaf: leafSpec{
  1431  			sans: []string{"dns:example.com"},
  1432  			ekus: []string{"serverAuth", "clientAuth"},
  1433  		},
  1434  		expectedError: "incompatible key usage",
  1435  	},
  1436  	{
  1437  		name:  "msSGC EKU does not permit server/client auth",
  1438  		roots: make([]constraintsSpec, 1),
  1439  		intermediates: [][]constraintsSpec{
  1440  			{
  1441  				{
  1442  					ekus: []string{"msSGC"},
  1443  				},
  1444  			},
  1445  		},
  1446  		leaf: leafSpec{
  1447  			sans: []string{"dns:example.com"},
  1448  			ekus: []string{"serverAuth", "clientAuth"},
  1449  		},
  1450  		expectedError: "incompatible key usage",
  1451  	},
  1452  	{
  1453  		name: "empty DNS permitted constraint allows anything",
  1454  		roots: []constraintsSpec{
  1455  			{
  1456  				ok: []string{"dns:"},
  1457  			},
  1458  		},
  1459  		intermediates: [][]constraintsSpec{
  1460  			{
  1461  				{},
  1462  			},
  1463  		},
  1464  		leaf: leafSpec{
  1465  			sans: []string{"dns:example.com"},
  1466  		},
  1467  	},
  1468  	{
  1469  		name: "empty DNS excluded constraint rejects everything",
  1470  		roots: []constraintsSpec{
  1471  			{
  1472  				bad: []string{"dns:"},
  1473  			},
  1474  		},
  1475  		intermediates: [][]constraintsSpec{
  1476  			{
  1477  				{},
  1478  			},
  1479  		},
  1480  		leaf: leafSpec{
  1481  			sans: []string{"dns:example.com"},
  1482  		},
  1483  		expectedError: "\"example.com\" is excluded",
  1484  	},
  1485  	{
  1486  		name: "empty email permitted constraint allows anything",
  1487  		roots: []constraintsSpec{
  1488  			{
  1489  				ok: []string{"email:"},
  1490  			},
  1491  		},
  1492  		intermediates: [][]constraintsSpec{
  1493  			{
  1494  				{},
  1495  			},
  1496  		},
  1497  		leaf: leafSpec{
  1498  			sans: []string{"email:foo@example.com"},
  1499  		},
  1500  	},
  1501  	{
  1502  		name: "empty email excluded constraint rejects everything",
  1503  		roots: []constraintsSpec{
  1504  			{
  1505  				bad: []string{"email:"},
  1506  			},
  1507  		},
  1508  		intermediates: [][]constraintsSpec{
  1509  			{
  1510  				{},
  1511  			},
  1512  		},
  1513  		leaf: leafSpec{
  1514  			sans: []string{"email:foo@example.com"},
  1515  		},
  1516  		expectedError: "\"foo@example.com\" is excluded",
  1517  	},
  1518  	{
  1519  		name: "empty URI permitted constraint allows anything",
  1520  		roots: []constraintsSpec{
  1521  			{
  1522  				ok: []string{"uri:"},
  1523  			},
  1524  		},
  1525  		intermediates: [][]constraintsSpec{
  1526  			{
  1527  				{},
  1528  			},
  1529  		},
  1530  		leaf: leafSpec{
  1531  			sans: []string{"uri:https://example.com/test"},
  1532  		},
  1533  	},
  1534  	{
  1535  		name: "empty URI excluded constraint rejects everything",
  1536  		roots: []constraintsSpec{
  1537  			{
  1538  				bad: []string{"uri:"},
  1539  			},
  1540  		},
  1541  		intermediates: [][]constraintsSpec{
  1542  			{
  1543  				{},
  1544  			},
  1545  		},
  1546  		leaf: leafSpec{
  1547  			sans: []string{"uri:https://example.com/test"},
  1548  		},
  1549  		expectedError: "\"https://example.com/test\" is excluded",
  1550  	},
  1551  	{
  1552  		name:  "serverAuth EKU does not permit clientAuth",
  1553  		roots: make([]constraintsSpec, 1),
  1554  		intermediates: [][]constraintsSpec{
  1555  			{
  1556  				{},
  1557  			},
  1558  		},
  1559  		leaf: leafSpec{
  1560  			sans: []string{"dns:example.com"},
  1561  			ekus: []string{"serverAuth"},
  1562  		},
  1563  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
  1564  		expectedError: "incompatible key usage",
  1565  	},
  1566  	{
  1567  		name:  "msSGC EKU does not permit serverAuth",
  1568  		roots: make([]constraintsSpec, 1),
  1569  		intermediates: [][]constraintsSpec{
  1570  			{
  1571  				{},
  1572  			},
  1573  		},
  1574  		leaf: leafSpec{
  1575  			sans: []string{"dns:example.com"},
  1576  			ekus: []string{"msSGC"},
  1577  		},
  1578  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  1579  		expectedError: "incompatible key usage",
  1580  	},
  1581  	{
  1582  		// An invalid DNS SAN should be detected only at validation time so
  1583  		// that we can process CA certificates in the wild that have invalid SANs.
  1584  		// See https://github.com/golang/go/issues/23995
  1585  		name:  "invalid SANs are ignored with no constraints",
  1586  		roots: make([]constraintsSpec, 1),
  1587  		intermediates: [][]constraintsSpec{
  1588  			{
  1589  				{},
  1590  			},
  1591  		},
  1592  		leaf: leafSpec{
  1593  			sans: []string{"dns:this is invalid", "email:this @ is invalid"},
  1594  		},
  1595  	},
  1596  	{
  1597  		name: "invalid DNS SAN detected with constraints",
  1598  		roots: []constraintsSpec{
  1599  			{
  1600  				bad: []string{"uri:"},
  1601  			},
  1602  		},
  1603  		intermediates: [][]constraintsSpec{
  1604  			{
  1605  				{},
  1606  			},
  1607  		},
  1608  		leaf: leafSpec{
  1609  			sans: []string{"dns:this is invalid"},
  1610  		},
  1611  		expectedError: "cannot parse dnsName",
  1612  	},
  1613  	{
  1614  		name: "invalid email SAN detected with constraints",
  1615  		roots: []constraintsSpec{
  1616  			{
  1617  				bad: []string{"uri:"},
  1618  			},
  1619  		},
  1620  		intermediates: [][]constraintsSpec{
  1621  			{
  1622  				{},
  1623  			},
  1624  		},
  1625  		leaf: leafSpec{
  1626  			sans: []string{"email:this @ is invalid"},
  1627  		},
  1628  		expectedError: "cannot parse rfc822Name",
  1629  	},
  1630  	{
  1631  		name:  "any requested EKU is sufficient",
  1632  		roots: make([]constraintsSpec, 1),
  1633  		intermediates: [][]constraintsSpec{
  1634  			{
  1635  				{},
  1636  			},
  1637  		},
  1638  		leaf: leafSpec{
  1639  			sans: []string{"dns:example.com"},
  1640  			ekus: []string{"email"},
  1641  		},
  1642  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
  1643  	},
  1644  	{
  1645  		name:  "unrequested EKUs not required to be nested",
  1646  		roots: make([]constraintsSpec, 1),
  1647  		intermediates: [][]constraintsSpec{
  1648  			{
  1649  				{
  1650  					ekus: []string{"serverAuth"},
  1651  				},
  1652  			},
  1653  		},
  1654  		leaf: leafSpec{
  1655  			sans: []string{"dns:example.com"},
  1656  			// There's no email EKU in the intermediate. This would be rejected if
  1657  			// full nesting was required.
  1658  			ekus: []string{"email", "serverAuth"},
  1659  		},
  1660  	},
  1661  	{
  1662  		name: "empty leaf is accepted in constrained chain",
  1663  		roots: []constraintsSpec{
  1664  			{
  1665  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1666  			},
  1667  		},
  1668  		intermediates: [][]constraintsSpec{
  1669  			{
  1670  				{},
  1671  			},
  1672  		},
  1673  		leaf: leafSpec{
  1674  			sans: []string{},
  1675  		},
  1676  	},
  1677  	{
  1678  		name: "no SANs and non-hostname CN is accepted in constrained chain",
  1679  		roots: []constraintsSpec{
  1680  			{
  1681  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1682  			},
  1683  		},
  1684  		intermediates: [][]constraintsSpec{
  1685  			{
  1686  				{},
  1687  			},
  1688  		},
  1689  		leaf: leafSpec{
  1690  			sans: []string{},
  1691  			cn:   "foo.bar",
  1692  		},
  1693  	},
  1694  	{
  1695  		name: "constraints don't apply to CN",
  1696  		roots: []constraintsSpec{
  1697  			{
  1698  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1699  			},
  1700  		},
  1701  		intermediates: [][]constraintsSpec{
  1702  			{
  1703  				{},
  1704  			},
  1705  		},
  1706  		leaf: leafSpec{
  1707  			sans: []string{"dns:foo.com"},
  1708  			cn:   "foo.bar",
  1709  		},
  1710  	},
  1711  	{
  1712  		name:          "DNS SAN cannot use leading period form",
  1713  		roots:         []constraintsSpec{{ok: []string{"dns:example.com"}}},
  1714  		leaf:          leafSpec{sans: []string{"dns:.example.com"}},
  1715  		expectedError: "cannot parse dnsName \".example.com\"",
  1716  	},
  1717  	{
  1718  		name: "URI with IPv6 and zone is rejected",
  1719  		roots: []constraintsSpec{
  1720  			{
  1721  				ok: []string{"uri:example.com"},
  1722  			},
  1723  		},
  1724  		intermediates: [][]constraintsSpec{
  1725  			{
  1726  				{},
  1727  			},
  1728  		},
  1729  		leaf: leafSpec{
  1730  			sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
  1731  		},
  1732  		expectedError: "URI with IP",
  1733  	},
  1734  	{
  1735  		name: "intermediate can narrow permitted dns scope",
  1736  		roots: []constraintsSpec{
  1737  			{
  1738  				ok: []string{"dns:"},
  1739  			},
  1740  		},
  1741  		intermediates: [][]constraintsSpec{
  1742  			{
  1743  				{
  1744  					ok: []string{"dns:example.com"},
  1745  				},
  1746  			},
  1747  		},
  1748  		leaf: leafSpec{
  1749  			sans: []string{"dns:test.com"},
  1750  		},
  1751  		expectedError: "\"test.com\" is not permitted",
  1752  	},
  1753  	{
  1754  		name: "intermediate cannot narrow excluded dns scope",
  1755  		roots: []constraintsSpec{
  1756  			{
  1757  				bad: []string{"dns:"},
  1758  			},
  1759  		},
  1760  		intermediates: [][]constraintsSpec{
  1761  			{
  1762  				{
  1763  					bad: []string{"dns:example.com"},
  1764  				},
  1765  			},
  1766  		},
  1767  		leaf: leafSpec{
  1768  			sans: []string{"dns:test.com"},
  1769  		},
  1770  		expectedError: "\"test.com\" is excluded by constraint \"\"",
  1771  	},
  1772  	{
  1773  		name: "intermediate can narrow excluded dns scope",
  1774  		roots: []constraintsSpec{
  1775  			{
  1776  				bad: []string{"dns:example.com"},
  1777  			},
  1778  		},
  1779  		intermediates: [][]constraintsSpec{
  1780  			{
  1781  				{
  1782  					bad: []string{"dns:"},
  1783  				},
  1784  			},
  1785  		},
  1786  		leaf: leafSpec{
  1787  			sans: []string{"dns:test.com"},
  1788  		},
  1789  		expectedError: "\"test.com\" is excluded by constraint \"\"",
  1790  	},
  1791  	{
  1792  		name: "permitted dns constraint is not a prefix match",
  1793  		roots: []constraintsSpec{
  1794  			{
  1795  				ok: []string{"dns:example.com"},
  1796  			},
  1797  		},
  1798  		intermediates: [][]constraintsSpec{
  1799  			{
  1800  				{},
  1801  			},
  1802  		},
  1803  		leaf: leafSpec{
  1804  			sans: []string{"dns:testexample.com"},
  1805  		},
  1806  		expectedError: "\"testexample.com\" is not permitted",
  1807  	},
  1808  	{
  1809  		name: "subdomain constraint does not allow wildcard",
  1810  		roots: []constraintsSpec{
  1811  			{
  1812  				ok: []string{"dns:a.com", "dns:foo.example.com", "dns:z.com"},
  1813  			},
  1814  		},
  1815  		intermediates: [][]constraintsSpec{
  1816  			{
  1817  				{},
  1818  			},
  1819  		},
  1820  		leaf: leafSpec{
  1821  			sans: []string{"dns:*.example.com"},
  1822  		},
  1823  		expectedError: "\"*.example.com\" is not permitted",
  1824  	},
  1825  	{
  1826  		name: "excluded dns constraint is not a prefix match",
  1827  		roots: []constraintsSpec{
  1828  			{
  1829  				bad: []string{"dns:example.com"},
  1830  			},
  1831  		},
  1832  		intermediates: [][]constraintsSpec{
  1833  			{
  1834  				{},
  1835  			},
  1836  		},
  1837  		leaf: leafSpec{
  1838  			sans: []string{"dns:testexample.com"},
  1839  		},
  1840  	},
  1841  	{
  1842  		name: "excluded email constraint, multiple email with matching local portion",
  1843  		roots: []constraintsSpec{
  1844  			{
  1845  				bad: []string{"email:a@example.com", "email:a@test.com"},
  1846  			},
  1847  		},
  1848  		intermediates: [][]constraintsSpec{
  1849  			{
  1850  				{},
  1851  			},
  1852  		},
  1853  		leaf: leafSpec{
  1854  			sans: []string{"email:a@example.com"},
  1855  		},
  1856  		expectedError: "\"a@example.com\" is excluded by constraint \"a@example.com\"",
  1857  	},
  1858  	{
  1859  		name: "email_case_check",
  1860  		roots: []constraintsSpec{
  1861  			{
  1862  				ok: []string{"email:a@example.com"},
  1863  			},
  1864  		},
  1865  		intermediates: [][]constraintsSpec{
  1866  			{
  1867  				{},
  1868  			},
  1869  		},
  1870  		leaf: leafSpec{
  1871  			sans: []string{"email:a@ExAmple.com"},
  1872  		},
  1873  	},
  1874  	{
  1875  		name: "excluded constraint, empty DNS san",
  1876  		roots: []constraintsSpec{
  1877  			{
  1878  				bad: []string{"dns:example.com"},
  1879  			},
  1880  		},
  1881  		leaf: leafSpec{
  1882  			sans: []string{"dns:"},
  1883  		},
  1884  	},
  1885  
  1886  	{
  1887  		name: "subdomain excluded constraints preclude outer wildcard names",
  1888  		roots: []constraintsSpec{
  1889  			{
  1890  				bad: []string{"dns:foo.example.com"},
  1891  			},
  1892  		},
  1893  		intermediates: [][]constraintsSpec{
  1894  			{
  1895  				{},
  1896  			},
  1897  		},
  1898  		leaf: leafSpec{
  1899  			sans: []string{"dns:*.example.com"},
  1900  		},
  1901  		expectedError: "\"*.example.com\" is excluded by constraint \"foo.example.com\"",
  1902  	},
  1903  	{
  1904  		name: "subdomain excluded constraints do not preclude far outer wildcard names",
  1905  		roots: []constraintsSpec{
  1906  			{
  1907  				bad: []string{"dns:foo.example.com"},
  1908  			},
  1909  		},
  1910  		intermediates: [][]constraintsSpec{
  1911  			{
  1912  				{},
  1913  			},
  1914  		},
  1915  		leaf: leafSpec{
  1916  			sans: []string{"dns:*.com"},
  1917  		},
  1918  	},
  1919  	{
  1920  		name: "subdomain excluded constraints preclude inner wildcard names",
  1921  		roots: []constraintsSpec{
  1922  			{
  1923  				bad: []string{"dns:foo.example.com"},
  1924  			},
  1925  		},
  1926  		intermediates: [][]constraintsSpec{
  1927  			{
  1928  				{},
  1929  			},
  1930  		},
  1931  		leaf: leafSpec{
  1932  			sans: []string{"dns:*.foo.example.com"},
  1933  		},
  1934  		expectedError: "\"*.foo.example.com\" is excluded by constraint \"foo.example.com\"",
  1935  	},
  1936  	{
  1937  		name: "subdomain excluded constraints preclude far inner wildcard names",
  1938  		roots: []constraintsSpec{
  1939  			{
  1940  				bad: []string{"dns:foo.example.com"},
  1941  			},
  1942  		},
  1943  		intermediates: [][]constraintsSpec{
  1944  			{
  1945  				{},
  1946  			},
  1947  		},
  1948  		leaf: leafSpec{
  1949  			sans: []string{"dns:*.bar.foo.example.com"},
  1950  		},
  1951  		expectedError: "\"*.bar.foo.example.com\" is excluded by constraint \"foo.example.com\"",
  1952  	},
  1953  	{
  1954  		name: "outer wildcard names are not matched by subdomain permitted constraints",
  1955  		roots: []constraintsSpec{
  1956  			{
  1957  				ok: []string{"dns:foo.example.com"},
  1958  			},
  1959  		},
  1960  		intermediates: [][]constraintsSpec{
  1961  			{
  1962  				{},
  1963  			},
  1964  		},
  1965  		leaf: leafSpec{
  1966  			sans: []string{"dns:*.example.com"},
  1967  		},
  1968  		expectedError: "\"*.example.com\" is not permitted",
  1969  	},
  1970  	{
  1971  		name: "far outer wildcard names are not matched by subdomain permitted constraints",
  1972  		roots: []constraintsSpec{
  1973  			{
  1974  				ok: []string{"dns:foo.example.com"},
  1975  			},
  1976  		},
  1977  		intermediates: [][]constraintsSpec{
  1978  			{
  1979  				{},
  1980  			},
  1981  		},
  1982  		leaf: leafSpec{
  1983  			sans: []string{"dns:*.com"},
  1984  		},
  1985  		expectedError: "\"*.com\" is not permitted",
  1986  	},
  1987  	{
  1988  		name: "inner wildcard names are matched by subdomain permitted constraints",
  1989  		roots: []constraintsSpec{
  1990  			{
  1991  				ok: []string{"dns:foo.example.com"},
  1992  			},
  1993  		},
  1994  		intermediates: [][]constraintsSpec{
  1995  			{
  1996  				{},
  1997  			},
  1998  		},
  1999  		leaf: leafSpec{
  2000  			sans: []string{"dns:*.foo.example.com"},
  2001  		},
  2002  	},
  2003  	{
  2004  		name: "far inner wildcard names are matched by subdomain permitted constraints",
  2005  		roots: []constraintsSpec{
  2006  			{
  2007  				ok: []string{"dns:foo.example.com"},
  2008  			},
  2009  		},
  2010  		intermediates: [][]constraintsSpec{
  2011  			{
  2012  				{},
  2013  			},
  2014  		},
  2015  		leaf: leafSpec{
  2016  			sans: []string{"dns:*.bar.foo.example.com"},
  2017  		},
  2018  	},
  2019  
  2020  	{
  2021  		name: "cross include should not match",
  2022  		roots: []constraintsSpec{
  2023  			{
  2024  				ok: []string{"dns:foo.example.com"},
  2025  			},
  2026  		},
  2027  		intermediates: [][]constraintsSpec{
  2028  			{
  2029  				{},
  2030  			},
  2031  		},
  2032  		leaf: leafSpec{
  2033  			sans: []string{"dns:*.bar.example.com"},
  2034  		},
  2035  		expectedError: "\"*.bar.example.com\" is not permitted by any constraint",
  2036  	},
  2037  	{
  2038  		name: "cross exclude should not match",
  2039  		roots: []constraintsSpec{
  2040  			{
  2041  				bad: []string{"dns:foo.example.com"},
  2042  			},
  2043  		},
  2044  		intermediates: [][]constraintsSpec{
  2045  			{
  2046  				{},
  2047  			},
  2048  		},
  2049  		leaf: leafSpec{
  2050  			sans: []string{"dns:*.bar.example.com"},
  2051  		},
  2052  	},
  2053  	{
  2054  		name: "subdomain exclusion blocks uppercase wildcard",
  2055  		roots: []constraintsSpec{{
  2056  			bad: []string{"dns:sub.example.com"},
  2057  		}},
  2058  		intermediates: [][]constraintsSpec{{{}}},
  2059  		leaf: leafSpec{
  2060  			sans: []string{"dns:*.EXAMPLE.COM"},
  2061  		},
  2062  		expectedError: "\"*.EXAMPLE.COM\" is excluded by constraint \"sub.example.com\"",
  2063  	},
  2064  	{
  2065  		name: "uppercase subdomain exclusion blocks lowercase wildcard",
  2066  		roots: []constraintsSpec{{
  2067  			bad: []string{"dns:SUB.EXAMPLE.COM"},
  2068  		}},
  2069  		intermediates: [][]constraintsSpec{{{}}},
  2070  		leaf: leafSpec{
  2071  			sans: []string{"dns:*.example.com"},
  2072  		},
  2073  		expectedError: "\"*.example.com\" is excluded by constraint \"sub.example.com\"",
  2074  	},
  2075  }
  2076  
  2077  func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  2078  	var serialBytes [16]byte
  2079  	rand.Read(serialBytes[:])
  2080  
  2081  	template := &Certificate{
  2082  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  2083  		Subject: pkix.Name{
  2084  			CommonName: name,
  2085  		},
  2086  		NotBefore:             time.Unix(1000, 0),
  2087  		NotAfter:              time.Unix(2000, 0),
  2088  		KeyUsage:              KeyUsageCertSign,
  2089  		BasicConstraintsValid: true,
  2090  		IsCA:                  true,
  2091  	}
  2092  
  2093  	if err := addConstraintsToTemplate(constraints, template); err != nil {
  2094  		return nil, err
  2095  	}
  2096  
  2097  	if parent == nil {
  2098  		parent = template
  2099  	}
  2100  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  2101  	if err != nil {
  2102  		return nil, err
  2103  	}
  2104  
  2105  	caCert, err := ParseCertificate(derBytes)
  2106  	if err != nil {
  2107  		return nil, err
  2108  	}
  2109  
  2110  	return caCert, nil
  2111  }
  2112  
  2113  func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  2114  	var serialBytes [16]byte
  2115  	rand.Read(serialBytes[:])
  2116  
  2117  	template := &Certificate{
  2118  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  2119  		Subject: pkix.Name{
  2120  			OrganizationalUnit: []string{"Leaf"},
  2121  			CommonName:         leaf.cn,
  2122  		},
  2123  		NotBefore:             time.Unix(1000, 0),
  2124  		NotAfter:              time.Unix(2000, 0),
  2125  		KeyUsage:              KeyUsageDigitalSignature,
  2126  		BasicConstraintsValid: true,
  2127  		IsCA:                  false,
  2128  	}
  2129  
  2130  	for _, name := range leaf.sans {
  2131  		switch {
  2132  		case strings.HasPrefix(name, "dns:"):
  2133  			template.DNSNames = append(template.DNSNames, name[4:])
  2134  
  2135  		case strings.HasPrefix(name, "ip:"):
  2136  			ip := net.ParseIP(name[3:])
  2137  			if ip == nil {
  2138  				return nil, fmt.Errorf("cannot parse IP %q", name[3:])
  2139  			}
  2140  			template.IPAddresses = append(template.IPAddresses, ip)
  2141  
  2142  		case strings.HasPrefix(name, "invalidip:"):
  2143  			ipBytes, err := hex.DecodeString(name[10:])
  2144  			if err != nil {
  2145  				return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
  2146  			}
  2147  			template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
  2148  
  2149  		case strings.HasPrefix(name, "email:"):
  2150  			template.EmailAddresses = append(template.EmailAddresses, name[6:])
  2151  
  2152  		case strings.HasPrefix(name, "uri:"):
  2153  			uri, err := url.Parse(name[4:])
  2154  			if err != nil {
  2155  				return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
  2156  			}
  2157  			template.URIs = append(template.URIs, uri)
  2158  
  2159  		case strings.HasPrefix(name, "unknown:"):
  2160  			// This is a special case for testing unknown
  2161  			// name types. A custom SAN extension is
  2162  			// injected into the certificate.
  2163  			if len(leaf.sans) != 1 {
  2164  				panic("when using unknown name types, it must be the sole name")
  2165  			}
  2166  
  2167  			template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
  2168  				Id: []int{2, 5, 29, 17},
  2169  				Value: []byte{
  2170  					0x30, // SEQUENCE
  2171  					3,    // three bytes
  2172  					9,    // undefined GeneralName type 9
  2173  					1,
  2174  					1,
  2175  				},
  2176  			})
  2177  
  2178  		default:
  2179  			return nil, fmt.Errorf("unknown name type %q", name)
  2180  		}
  2181  	}
  2182  
  2183  	var err error
  2184  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
  2185  		return nil, err
  2186  	}
  2187  
  2188  	if parent == nil {
  2189  		parent = template
  2190  	}
  2191  
  2192  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  2193  	if err != nil {
  2194  		return nil, err
  2195  	}
  2196  
  2197  	return ParseCertificate(derBytes)
  2198  }
  2199  
  2200  func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
  2201  	appendConstraint := func(contents []byte, tag uint8) []byte {
  2202  		contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
  2203  		contents = append(contents, byte(4+len(constraint)) /* length */)
  2204  		contents = append(contents, 0x30 /* SEQUENCE */)
  2205  		contents = append(contents, byte(2+len(constraint)) /* length */)
  2206  		contents = append(contents, byte(typeNum) /* GeneralName type */)
  2207  		contents = append(contents, byte(len(constraint)))
  2208  		return append(contents, constraint...)
  2209  	}
  2210  
  2211  	var contents []byte
  2212  	if !isExcluded {
  2213  		contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
  2214  	} else {
  2215  		contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
  2216  	}
  2217  
  2218  	var value []byte
  2219  	value = append(value, 0x30 /* SEQUENCE */)
  2220  	value = append(value, byte(len(contents)))
  2221  	value = append(value, contents...)
  2222  
  2223  	return pkix.Extension{
  2224  		Id:    []int{2, 5, 29, 30},
  2225  		Value: value,
  2226  	}
  2227  }
  2228  
  2229  func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
  2230  	parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
  2231  		for _, constraint := range constraints {
  2232  			switch {
  2233  			case strings.HasPrefix(constraint, "dns:"):
  2234  				dnsNames = append(dnsNames, constraint[4:])
  2235  
  2236  			case strings.HasPrefix(constraint, "ip:"):
  2237  				_, ipNet, err := net.ParseCIDR(constraint[3:])
  2238  				if err != nil {
  2239  					return nil, nil, nil, nil, err
  2240  				}
  2241  				ips = append(ips, ipNet)
  2242  
  2243  			case strings.HasPrefix(constraint, "email:"):
  2244  				emailAddrs = append(emailAddrs, constraint[6:])
  2245  
  2246  			case strings.HasPrefix(constraint, "uri:"):
  2247  				uriDomains = append(uriDomains, constraint[4:])
  2248  
  2249  			default:
  2250  				return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
  2251  			}
  2252  		}
  2253  
  2254  		return dnsNames, ips, emailAddrs, uriDomains, err
  2255  	}
  2256  
  2257  	handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
  2258  		switch {
  2259  		case constraint == "unknown:":
  2260  			template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
  2261  
  2262  		default:
  2263  			return false
  2264  		}
  2265  
  2266  		return true
  2267  	}
  2268  
  2269  	if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
  2270  		if handleSpecialConstraint(constraints.ok[0], false) {
  2271  			return nil
  2272  		}
  2273  	}
  2274  
  2275  	if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
  2276  		if handleSpecialConstraint(constraints.bad[0], true) {
  2277  			return nil
  2278  		}
  2279  	}
  2280  
  2281  	var err error
  2282  	template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
  2283  	if err != nil {
  2284  		return err
  2285  	}
  2286  
  2287  	template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
  2288  	if err != nil {
  2289  		return err
  2290  	}
  2291  
  2292  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
  2293  		return err
  2294  	}
  2295  
  2296  	return nil
  2297  }
  2298  
  2299  func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
  2300  	for _, s := range ekuStrs {
  2301  		switch s {
  2302  		case "serverAuth":
  2303  			ekus = append(ekus, ExtKeyUsageServerAuth)
  2304  		case "clientAuth":
  2305  			ekus = append(ekus, ExtKeyUsageClientAuth)
  2306  		case "email":
  2307  			ekus = append(ekus, ExtKeyUsageEmailProtection)
  2308  		case "netscapeSGC":
  2309  			ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
  2310  		case "msSGC":
  2311  			ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
  2312  		case "any":
  2313  			ekus = append(ekus, ExtKeyUsageAny)
  2314  		case "other":
  2315  			unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
  2316  		default:
  2317  			return nil, nil, fmt.Errorf("unknown EKU %q", s)
  2318  		}
  2319  	}
  2320  
  2321  	return
  2322  }
  2323  
  2324  func TestConstraintCases(t *testing.T) {
  2325  	privateKeys := sync.Pool{
  2326  		New: func() any {
  2327  			priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2328  			if err != nil {
  2329  				panic(err)
  2330  			}
  2331  			return priv
  2332  		},
  2333  	}
  2334  
  2335  	for i, test := range nameConstraintsTests {
  2336  		t.Run(test.name, func(t *testing.T) {
  2337  			rootPool := NewCertPool()
  2338  			rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
  2339  			rootName := "Root " + strconv.Itoa(i)
  2340  
  2341  			// keys keeps track of all the private keys used in a given
  2342  			// test and puts them back in the privateKeys pool at the end.
  2343  			keys := []*ecdsa.PrivateKey{rootKey}
  2344  
  2345  			// At each level (root, intermediate(s), leaf), parent points to
  2346  			// an example parent certificate and parentKey the key for the
  2347  			// parent level. Since all certificates at a given level have
  2348  			// the same name and public key, any parent certificate is
  2349  			// sufficient to get the correct issuer name and authority
  2350  			// key ID.
  2351  			var parent *Certificate
  2352  			parentKey := rootKey
  2353  
  2354  			for _, root := range test.roots {
  2355  				rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
  2356  				if err != nil {
  2357  					t.Fatalf("failed to create root: %s", err)
  2358  				}
  2359  
  2360  				parent = rootCert
  2361  				rootPool.AddCert(rootCert)
  2362  			}
  2363  
  2364  			intermediatePool := NewCertPool()
  2365  
  2366  			for level, intermediates := range test.intermediates {
  2367  				levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
  2368  				keys = append(keys, levelKey)
  2369  				levelName := "Intermediate level " + strconv.Itoa(level)
  2370  				var last *Certificate
  2371  
  2372  				for _, intermediate := range intermediates {
  2373  					caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
  2374  					if err != nil {
  2375  						t.Fatalf("failed to create %q: %s", levelName, err)
  2376  					}
  2377  
  2378  					last = caCert
  2379  					intermediatePool.AddCert(caCert)
  2380  				}
  2381  
  2382  				parent = last
  2383  				parentKey = levelKey
  2384  			}
  2385  
  2386  			leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
  2387  			keys = append(keys, leafKey)
  2388  
  2389  			leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
  2390  			if err != nil {
  2391  				t.Fatalf("cannot create leaf: %s", err)
  2392  			}
  2393  
  2394  			// Skip tests with CommonName set because OpenSSL will try to match it
  2395  			// against name constraints, while we ignore it when it's not hostname-looking.
  2396  			if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
  2397  				output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
  2398  				if err == nil && len(test.expectedError) > 0 {
  2399  					t.Error("unexpectedly succeeded against OpenSSL")
  2400  					if debugOpenSSLFailure {
  2401  						return
  2402  					}
  2403  				}
  2404  
  2405  				if err != nil {
  2406  					if _, ok := err.(*exec.ExitError); !ok {
  2407  						t.Errorf("OpenSSL failed to run: %s", err)
  2408  					} else if len(test.expectedError) == 0 {
  2409  						t.Errorf("OpenSSL unexpectedly failed: %v", output)
  2410  						if debugOpenSSLFailure {
  2411  							return
  2412  						}
  2413  					}
  2414  				}
  2415  			}
  2416  
  2417  			verifyOpts := VerifyOptions{
  2418  				Roots:         rootPool,
  2419  				Intermediates: intermediatePool,
  2420  				CurrentTime:   time.Unix(1500, 0),
  2421  				KeyUsages:     test.requestedEKUs,
  2422  			}
  2423  			_, err = leafCert.Verify(verifyOpts)
  2424  
  2425  			logInfo := false
  2426  			if len(test.expectedError) == 0 {
  2427  				if err != nil {
  2428  					t.Errorf("unexpected failure: %s", err)
  2429  				} else {
  2430  					logInfo = false
  2431  				}
  2432  			} else {
  2433  				if err == nil {
  2434  					t.Error("unexpected success")
  2435  				} else if !strings.Contains(err.Error(), test.expectedError) {
  2436  					t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
  2437  				} else {
  2438  					logInfo = false
  2439  				}
  2440  			}
  2441  
  2442  			if logInfo {
  2443  				certAsPEM := func(cert *Certificate) string {
  2444  					var buf bytes.Buffer
  2445  					pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
  2446  					return buf.String()
  2447  				}
  2448  				t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
  2449  				if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
  2450  					for ii, intermediate := range intermediates {
  2451  						t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
  2452  					}
  2453  				}
  2454  				t.Errorf("leaf:\n%s", certAsPEM(leafCert))
  2455  			}
  2456  
  2457  			for _, key := range keys {
  2458  				privateKeys.Put(key)
  2459  			}
  2460  		})
  2461  	}
  2462  }
  2463  
  2464  func TestNameConstraintIPNonZeroHostBits(t *testing.T) {
  2465  	rootKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2466  	if err != nil {
  2467  		t.Fatal(err)
  2468  	}
  2469  	leafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2470  	if err != nil {
  2471  		t.Fatal(err)
  2472  	}
  2473  
  2474  	// Two excluded iPAddress subtrees: a lower-addressed range that takes the
  2475  	// binary-search neighbor slot, and one whose address has host bits set
  2476  	// (10.10.10.10/16, i.e. network 10.10.0.0/16).
  2477  	subtree := func(b ...byte) []byte {
  2478  		gn := append([]byte{0x87, byte(len(b))}, b...)
  2479  		return append([]byte{0x30, byte(len(gn))}, gn...)
  2480  	}
  2481  	var subtrees []byte
  2482  	subtrees = append(subtrees, subtree(10, 0, 0, 0, 255, 255, 255, 252)...)
  2483  	subtrees = append(subtrees, subtree(10, 10, 10, 10, 255, 255, 0, 0)...)
  2484  	excluded := append([]byte{0xa1, byte(len(subtrees))}, subtrees...)
  2485  	ncValue := append([]byte{0x30, byte(len(excluded))}, excluded...)
  2486  
  2487  	var serial [16]byte
  2488  	rand.Read(serial[:])
  2489  	rootTmpl := &Certificate{
  2490  		SerialNumber:          new(big.Int).SetBytes(serial[:]),
  2491  		Subject:               pkix.Name{CommonName: "Root"},
  2492  		NotBefore:             time.Unix(1000, 0),
  2493  		NotAfter:              time.Unix(2000, 0),
  2494  		KeyUsage:              KeyUsageCertSign,
  2495  		BasicConstraintsValid: true,
  2496  		IsCA:                  true,
  2497  		ExtraExtensions: []pkix.Extension{
  2498  			{Id: []int{2, 5, 29, 30}, Critical: true, Value: ncValue},
  2499  		},
  2500  	}
  2501  	rootDER, err := CreateCertificate(rand.Reader, rootTmpl, rootTmpl, &rootKey.PublicKey, rootKey)
  2502  	if err != nil {
  2503  		t.Fatal(err)
  2504  	}
  2505  	root, err := ParseCertificate(rootDER)
  2506  	if err != nil {
  2507  		t.Fatal(err)
  2508  	}
  2509  
  2510  	// The parsed range must keep the address as encoded, host bits and all.
  2511  	if len(root.ExcludedIPRanges) != 2 {
  2512  		t.Fatalf("got %d excluded IP ranges, want 2", len(root.ExcludedIPRanges))
  2513  	}
  2514  	if got := root.ExcludedIPRanges[1].IP; !got.Equal(net.IP{10, 10, 10, 10}) {
  2515  		t.Errorf("excluded range IP = %v, want 10.10.10.10", got)
  2516  	}
  2517  
  2518  	leaf, err := makeConstraintsLeafCert(leafSpec{sans: []string{"ip:10.10.0.1"}}, leafKey, root, rootKey)
  2519  	if err != nil {
  2520  		t.Fatal(err)
  2521  	}
  2522  
  2523  	roots := NewCertPool()
  2524  	roots.AddCert(root)
  2525  	if _, err := leaf.Verify(VerifyOptions{Roots: roots, CurrentTime: time.Unix(1500, 0)}); err == nil {
  2526  		t.Error("leaf with IP SAN inside excluded range was accepted")
  2527  	} else if !strings.Contains(err.Error(), "excluded by constraint") {
  2528  		t.Errorf("got error %q, want excluded-by-constraint", err)
  2529  	}
  2530  }
  2531  
  2532  func writePEMsToTempFile(certs []*Certificate) *os.File {
  2533  	file, err := os.CreateTemp("", "name_constraints_test")
  2534  	if err != nil {
  2535  		panic("cannot create tempfile")
  2536  	}
  2537  
  2538  	pemBlock := &pem.Block{Type: "CERTIFICATE"}
  2539  	for _, cert := range certs {
  2540  		pemBlock.Bytes = cert.Raw
  2541  		pem.Encode(file, pemBlock)
  2542  	}
  2543  
  2544  	return file
  2545  }
  2546  
  2547  func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
  2548  	args := []string{"verify", "-no_check_time"}
  2549  
  2550  	rootsFile := writePEMsToTempFile(allCerts(t, roots))
  2551  	if debugOpenSSLFailure {
  2552  		println("roots file:", rootsFile.Name())
  2553  	} else {
  2554  		defer os.Remove(rootsFile.Name())
  2555  	}
  2556  	args = append(args, "-CAfile", rootsFile.Name())
  2557  
  2558  	if intermediates.len() > 0 {
  2559  		intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
  2560  		if debugOpenSSLFailure {
  2561  			println("intermediates file:", intermediatesFile.Name())
  2562  		} else {
  2563  			defer os.Remove(intermediatesFile.Name())
  2564  		}
  2565  		args = append(args, "-untrusted", intermediatesFile.Name())
  2566  	}
  2567  
  2568  	leafFile := writePEMsToTempFile([]*Certificate{leaf})
  2569  	if debugOpenSSLFailure {
  2570  		println("leaf file:", leafFile.Name())
  2571  	} else {
  2572  		defer os.Remove(leafFile.Name())
  2573  	}
  2574  	args = append(args, leafFile.Name())
  2575  
  2576  	cmd := testenv.Command(t, "openssl", args...)
  2577  	out, err := cmd.CombinedOutput()
  2578  	return string(out), err
  2579  }
  2580  
  2581  var rfc2821Tests = []struct {
  2582  	in                string
  2583  	localPart, domain string
  2584  }{
  2585  	{"foo@example.com", "foo", "example.com"},
  2586  	{"@example.com", "", ""},
  2587  	{"\"@example.com", "", ""},
  2588  	{"\"\"@example.com", "", "example.com"},
  2589  	{"\"a\"@example.com", "a", "example.com"},
  2590  	{"\"\\a\"@example.com", "a", "example.com"},
  2591  	{"a\"@example.com", "", ""},
  2592  	{"foo..bar@example.com", "", ""},
  2593  	{".foo.bar@example.com", "", ""},
  2594  	{"foo.bar.@example.com", "", ""},
  2595  	{"|{}?'@example.com", "|{}?'", "example.com"},
  2596  	{"a@b@c.com", "", ""},
  2597  
  2598  	// Examples from RFC 3696
  2599  	{"Abc\\@def@example.com", "Abc@def", "example.com"},
  2600  	{"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
  2601  	{"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
  2602  	{"\"Abc@def\"@example.com", "Abc@def", "example.com"},
  2603  	{"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
  2604  	{"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
  2605  	{"$A12345@example.com", "$A12345", "example.com"},
  2606  	{"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
  2607  	{"_somename@example.com", "_somename", "example.com"},
  2608  }
  2609  
  2610  func TestRFC2821Parsing(t *testing.T) {
  2611  	for i, test := range rfc2821Tests {
  2612  		mailbox, ok := parseRFC2821Mailbox(test.in)
  2613  		expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
  2614  
  2615  		if ok && expectedFailure {
  2616  			t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
  2617  			continue
  2618  		}
  2619  
  2620  		if !ok && !expectedFailure {
  2621  			t.Errorf("#%d: unexpected failure for %q", i, test.in)
  2622  			continue
  2623  		}
  2624  
  2625  		if !ok {
  2626  			continue
  2627  		}
  2628  
  2629  		if mailbox.local != test.localPart || mailbox.domain != test.domain {
  2630  			t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
  2631  		}
  2632  	}
  2633  }
  2634  
  2635  func TestBadNamesInConstraints(t *testing.T) {
  2636  	constraintParseError := func(err error) bool {
  2637  		str := err.Error()
  2638  		return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
  2639  	}
  2640  
  2641  	encodingError := func(err error) bool {
  2642  		return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
  2643  	}
  2644  
  2645  	// Bad names in constraints should not parse.
  2646  	badNames := []struct {
  2647  		name    string
  2648  		matcher func(error) bool
  2649  	}{
  2650  		{"dns:foo.com.", constraintParseError},
  2651  		{"email:abc@foo.com.", constraintParseError},
  2652  		{"email:foo.com.", constraintParseError},
  2653  		{"uri:example.com.", constraintParseError},
  2654  		{"uri:1.2.3.4", constraintParseError},
  2655  		{"uri:ffff::1", constraintParseError},
  2656  		{"dns:not–hyphen.com", encodingError},
  2657  		{"email:foo@not–hyphen.com", encodingError},
  2658  		{"uri:not–hyphen.com", encodingError},
  2659  	}
  2660  
  2661  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2662  	if err != nil {
  2663  		panic(err)
  2664  	}
  2665  
  2666  	for _, test := range badNames {
  2667  		_, err := makeConstraintsCACert(constraintsSpec{
  2668  			ok: []string{test.name},
  2669  		}, "TestAbsoluteNamesInConstraints", priv, nil, priv)
  2670  
  2671  		if err == nil {
  2672  			t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
  2673  			continue
  2674  		} else {
  2675  			if !test.matcher(err) {
  2676  				t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
  2677  			}
  2678  		}
  2679  	}
  2680  }
  2681  
  2682  func TestBadNamesInSANs(t *testing.T) {
  2683  	// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
  2684  	// will parse and are tested in name constraint tests at the top of this
  2685  	// file.
  2686  	badNames := []string{
  2687  		"uri:https://example.com./dsf",
  2688  		"invalidip:0102",
  2689  		"invalidip:0102030405",
  2690  	}
  2691  
  2692  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2693  	if err != nil {
  2694  		panic(err)
  2695  	}
  2696  
  2697  	for _, badName := range badNames {
  2698  		_, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
  2699  
  2700  		if err == nil {
  2701  			t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
  2702  			continue
  2703  		}
  2704  
  2705  		if str := err.Error(); !strings.Contains(str, "cannot parse ") {
  2706  			t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
  2707  		}
  2708  	}
  2709  }
  2710  

View as plain text