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 subdomain constraint",
   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  	},
   821  	{
   822  		name: "email subdomain constraint does not match parent",
   823  		roots: []constraintsSpec{
   824  			{
   825  				ok: []string{"email:.example.com"},
   826  			},
   827  		},
   828  		intermediates: [][]constraintsSpec{
   829  			{
   830  				{},
   831  			},
   832  		},
   833  		leaf: leafSpec{
   834  			sans: []string{"email:foo@example.com"},
   835  		},
   836  		expectedError: "\"foo@example.com\" is not permitted",
   837  	},
   838  	{
   839  		name: "email subdomain constraint matches deeper subdomains",
   840  		roots: []constraintsSpec{
   841  			{
   842  				ok: []string{"email:.example.com"},
   843  			},
   844  		},
   845  		intermediates: [][]constraintsSpec{
   846  			{
   847  				{},
   848  			},
   849  		},
   850  		leaf: leafSpec{
   851  			sans: []string{"email:foo@sub.sub.example.com"},
   852  		},
   853  	},
   854  	{
   855  		name: "email local part is case-sensitive",
   856  		roots: []constraintsSpec{
   857  			{
   858  				ok: []string{"email:foo@example.com"},
   859  			},
   860  		},
   861  		intermediates: [][]constraintsSpec{
   862  			{
   863  				{},
   864  			},
   865  		},
   866  		leaf: leafSpec{
   867  			sans: []string{"email:Foo@example.com"},
   868  		},
   869  		expectedError: "\"Foo@example.com\" is not permitted",
   870  	},
   871  	{
   872  		name: "email domain part is case-insensitive",
   873  		roots: []constraintsSpec{
   874  			{
   875  				ok: []string{"email:foo@EXAMPLE.com"},
   876  			},
   877  		},
   878  		intermediates: [][]constraintsSpec{
   879  			{
   880  				{},
   881  			},
   882  		},
   883  		leaf: leafSpec{
   884  			sans: []string{"email:foo@example.com"},
   885  		},
   886  	},
   887  	{
   888  		name: "DNS domain is case-insensitive",
   889  		roots: []constraintsSpec{
   890  			{
   891  				ok: []string{"dns:EXAMPLE.com"},
   892  			},
   893  		},
   894  		intermediates: [][]constraintsSpec{
   895  			{
   896  				{},
   897  			},
   898  		},
   899  		leaf: leafSpec{
   900  			sans: []string{"dns:example.com"},
   901  		},
   902  	},
   903  	{
   904  		name: "URI constraint covers host",
   905  		roots: []constraintsSpec{
   906  			{
   907  				ok: []string{"uri:example.com"},
   908  			},
   909  		},
   910  		intermediates: [][]constraintsSpec{
   911  			{
   912  				{},
   913  			},
   914  		},
   915  		leaf: leafSpec{
   916  			sans: []string{
   917  				"uri:http://example.com/bar",
   918  				"uri:http://example.com:8080/",
   919  				"uri:https://example.com/wibble#bar",
   920  			},
   921  		},
   922  	},
   923  	{
   924  		name: "URI with IP is rejected",
   925  		roots: []constraintsSpec{
   926  			{
   927  				ok: []string{"uri:example.com"},
   928  			},
   929  		},
   930  		intermediates: [][]constraintsSpec{
   931  			{
   932  				{},
   933  			},
   934  		},
   935  		leaf: leafSpec{
   936  			sans: []string{"uri:http://1.2.3.4/"},
   937  		},
   938  		expectedError: "URI with IP",
   939  	},
   940  	{
   941  		name: "URI with IP and port is rejected",
   942  		roots: []constraintsSpec{
   943  			{
   944  				ok: []string{"uri:example.com"},
   945  			},
   946  		},
   947  		intermediates: [][]constraintsSpec{
   948  			{
   949  				{},
   950  			},
   951  		},
   952  		leaf: leafSpec{
   953  			sans: []string{"uri:http://1.2.3.4:43/"},
   954  		},
   955  		expectedError: "URI with IP",
   956  	},
   957  	{
   958  		name: "URI with IPv6 is rejected",
   959  		roots: []constraintsSpec{
   960  			{
   961  				ok: []string{"uri:example.com"},
   962  			},
   963  		},
   964  		intermediates: [][]constraintsSpec{
   965  			{
   966  				{},
   967  			},
   968  		},
   969  		leaf: leafSpec{
   970  			sans: []string{"uri:http://[2006:abcd::1]/"},
   971  		},
   972  		expectedError: "URI with IP",
   973  	},
   974  	{
   975  		name: "URI with IPv6 and port is rejected",
   976  		roots: []constraintsSpec{
   977  			{
   978  				ok: []string{"uri:example.com"},
   979  			},
   980  		},
   981  		intermediates: [][]constraintsSpec{
   982  			{
   983  				{},
   984  			},
   985  		},
   986  		leaf: leafSpec{
   987  			sans: []string{"uri:http://[2006:abcd::1]:16/"},
   988  		},
   989  		expectedError: "URI with IP",
   990  	},
   991  	{
   992  		name: "URI permitted constraint is effective",
   993  		roots: []constraintsSpec{
   994  			{
   995  				ok: []string{"uri:example.com"},
   996  			},
   997  		},
   998  		intermediates: [][]constraintsSpec{
   999  			{
  1000  				{},
  1001  			},
  1002  		},
  1003  		leaf: leafSpec{
  1004  			sans: []string{"uri:http://bar.com/"},
  1005  		},
  1006  		expectedError: "\"http://bar.com/\" is not permitted",
  1007  	},
  1008  	{
  1009  		name: "URI excluded constraint is effective",
  1010  		roots: []constraintsSpec{
  1011  			{
  1012  				bad: []string{"uri:foo.com"},
  1013  			},
  1014  		},
  1015  		intermediates: [][]constraintsSpec{
  1016  			{
  1017  				{},
  1018  			},
  1019  		},
  1020  		leaf: leafSpec{
  1021  			sans: []string{"uri:http://foo.com/"},
  1022  		},
  1023  		expectedError: "\"http://foo.com/\" is excluded",
  1024  	},
  1025  	{
  1026  		name: "URI subdomain constraint",
  1027  		roots: []constraintsSpec{
  1028  			{
  1029  				ok: []string{"uri:.foo.com"},
  1030  			},
  1031  		},
  1032  		intermediates: [][]constraintsSpec{
  1033  			{
  1034  				{},
  1035  			},
  1036  		},
  1037  		leaf: leafSpec{
  1038  			sans: []string{"uri:http://www.foo.com/"},
  1039  		},
  1040  	},
  1041  	{
  1042  		name: "URI constraint not matched by URN",
  1043  		roots: []constraintsSpec{
  1044  			{
  1045  				ok: []string{"uri:example.com"},
  1046  			},
  1047  		},
  1048  		intermediates: [][]constraintsSpec{
  1049  			{
  1050  				{},
  1051  			},
  1052  		},
  1053  		leaf: leafSpec{
  1054  			sans: []string{"uri:urn:example"},
  1055  		},
  1056  		expectedError: "URI with empty host",
  1057  	},
  1058  	{
  1059  		name: "IPv6 exclusion does not exclude all IPv4",
  1060  		roots: []constraintsSpec{
  1061  			{
  1062  				ok:  []string{"ip:1.2.3.0/24"},
  1063  				bad: []string{"ip:::0/0"},
  1064  			},
  1065  		},
  1066  		intermediates: [][]constraintsSpec{
  1067  			{
  1068  				{},
  1069  			},
  1070  		},
  1071  		leaf: leafSpec{
  1072  			sans: []string{"ip:1.2.3.4"},
  1073  		},
  1074  	},
  1075  	{
  1076  		name:  "empty EKU in CA means any is ok",
  1077  		roots: make([]constraintsSpec, 1),
  1078  		intermediates: [][]constraintsSpec{
  1079  			{
  1080  				{},
  1081  			},
  1082  		},
  1083  		leaf: leafSpec{
  1084  			sans: []string{"dns:example.com"},
  1085  			ekus: []string{"serverAuth", "other"},
  1086  		},
  1087  	},
  1088  	{
  1089  		name:  "any EKU means any is ok",
  1090  		roots: make([]constraintsSpec, 1),
  1091  		intermediates: [][]constraintsSpec{
  1092  			{
  1093  				{
  1094  					ekus: []string{"any"},
  1095  				},
  1096  			},
  1097  		},
  1098  		leaf: leafSpec{
  1099  			sans: []string{"dns:example.com"},
  1100  			ekus: []string{"serverAuth", "other"},
  1101  		},
  1102  	},
  1103  	// default.)
  1104  	{
  1105  		name:  "intermediate with enumerated EKUs",
  1106  		roots: make([]constraintsSpec, 1),
  1107  		intermediates: [][]constraintsSpec{
  1108  			{
  1109  				{
  1110  					ekus: []string{"email"},
  1111  				},
  1112  			},
  1113  		},
  1114  		leaf: leafSpec{
  1115  			sans: []string{"dns:example.com"},
  1116  			ekus: []string{"serverAuth"},
  1117  		},
  1118  		expectedError: "incompatible key usage",
  1119  	},
  1120  	{
  1121  		name:  "unknown EKU in leaf",
  1122  		roots: make([]constraintsSpec, 1),
  1123  		intermediates: [][]constraintsSpec{
  1124  			{
  1125  				{
  1126  					ekus: []string{"email"},
  1127  				},
  1128  			},
  1129  		},
  1130  		leaf: leafSpec{
  1131  			sans: []string{"dns:example.com"},
  1132  			ekus: []string{"other"},
  1133  		},
  1134  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
  1135  	},
  1136  	// certificate doesn't use them.
  1137  	{
  1138  		name: "intermediate cannot add EKUs not in root if leaf uses them",
  1139  		roots: []constraintsSpec{
  1140  			{
  1141  				ekus: []string{"serverAuth"},
  1142  			},
  1143  		},
  1144  		intermediates: [][]constraintsSpec{
  1145  			{
  1146  				{
  1147  					ekus: []string{"serverAuth", "email"},
  1148  				},
  1149  			},
  1150  		},
  1151  		leaf: leafSpec{
  1152  			sans: []string{"dns:example.com"},
  1153  			ekus: []string{"serverAuth"},
  1154  		},
  1155  	},
  1156  	{
  1157  		name: "EKUs in root are effective",
  1158  		roots: []constraintsSpec{
  1159  			{
  1160  				ekus: []string{"email"},
  1161  			},
  1162  		},
  1163  		intermediates: [][]constraintsSpec{
  1164  			{
  1165  				{
  1166  					ekus: []string{"serverAuth"},
  1167  				},
  1168  			},
  1169  		},
  1170  		leaf: leafSpec{
  1171  			sans: []string{"dns:example.com"},
  1172  			ekus: []string{"serverAuth"},
  1173  		},
  1174  		expectedError: "incompatible key usage",
  1175  	},
  1176  	{
  1177  		name: "netscapeSGC EKU does not permit server/client auth",
  1178  		roots: []constraintsSpec{
  1179  			{},
  1180  		},
  1181  		intermediates: [][]constraintsSpec{
  1182  			{
  1183  				{
  1184  					ekus: []string{"netscapeSGC"},
  1185  				},
  1186  			},
  1187  		},
  1188  		leaf: leafSpec{
  1189  			sans: []string{"dns:example.com"},
  1190  			ekus: []string{"serverAuth", "clientAuth"},
  1191  		},
  1192  		expectedError: "incompatible key usage",
  1193  	},
  1194  	{
  1195  		name:  "msSGC EKU does not permit server/client auth",
  1196  		roots: make([]constraintsSpec, 1),
  1197  		intermediates: [][]constraintsSpec{
  1198  			{
  1199  				{
  1200  					ekus: []string{"msSGC"},
  1201  				},
  1202  			},
  1203  		},
  1204  		leaf: leafSpec{
  1205  			sans: []string{"dns:example.com"},
  1206  			ekus: []string{"serverAuth", "clientAuth"},
  1207  		},
  1208  		expectedError: "incompatible key usage",
  1209  	},
  1210  	{
  1211  		name: "empty DNS permitted constraint allows anything",
  1212  		roots: []constraintsSpec{
  1213  			{
  1214  				ok: []string{"dns:"},
  1215  			},
  1216  		},
  1217  		intermediates: [][]constraintsSpec{
  1218  			{
  1219  				{},
  1220  			},
  1221  		},
  1222  		leaf: leafSpec{
  1223  			sans: []string{"dns:example.com"},
  1224  		},
  1225  	},
  1226  	{
  1227  		name: "empty DNS excluded constraint rejects everything",
  1228  		roots: []constraintsSpec{
  1229  			{
  1230  				bad: []string{"dns:"},
  1231  			},
  1232  		},
  1233  		intermediates: [][]constraintsSpec{
  1234  			{
  1235  				{},
  1236  			},
  1237  		},
  1238  		leaf: leafSpec{
  1239  			sans: []string{"dns:example.com"},
  1240  		},
  1241  		expectedError: "\"example.com\" is excluded",
  1242  	},
  1243  	{
  1244  		name: "empty email permitted constraint allows anything",
  1245  		roots: []constraintsSpec{
  1246  			{
  1247  				ok: []string{"email:"},
  1248  			},
  1249  		},
  1250  		intermediates: [][]constraintsSpec{
  1251  			{
  1252  				{},
  1253  			},
  1254  		},
  1255  		leaf: leafSpec{
  1256  			sans: []string{"email:foo@example.com"},
  1257  		},
  1258  	},
  1259  	{
  1260  		name: "empty email excluded constraint rejects everything",
  1261  		roots: []constraintsSpec{
  1262  			{
  1263  				bad: []string{"email:"},
  1264  			},
  1265  		},
  1266  		intermediates: [][]constraintsSpec{
  1267  			{
  1268  				{},
  1269  			},
  1270  		},
  1271  		leaf: leafSpec{
  1272  			sans: []string{"email:foo@example.com"},
  1273  		},
  1274  		expectedError: "\"foo@example.com\" is excluded",
  1275  	},
  1276  	{
  1277  		name: "empty URI permitted constraint allows anything",
  1278  		roots: []constraintsSpec{
  1279  			{
  1280  				ok: []string{"uri:"},
  1281  			},
  1282  		},
  1283  		intermediates: [][]constraintsSpec{
  1284  			{
  1285  				{},
  1286  			},
  1287  		},
  1288  		leaf: leafSpec{
  1289  			sans: []string{"uri:https://example.com/test"},
  1290  		},
  1291  	},
  1292  	{
  1293  		name: "empty URI excluded constraint rejects everything",
  1294  		roots: []constraintsSpec{
  1295  			{
  1296  				bad: []string{"uri:"},
  1297  			},
  1298  		},
  1299  		intermediates: [][]constraintsSpec{
  1300  			{
  1301  				{},
  1302  			},
  1303  		},
  1304  		leaf: leafSpec{
  1305  			sans: []string{"uri:https://example.com/test"},
  1306  		},
  1307  		expectedError: "\"https://example.com/test\" is excluded",
  1308  	},
  1309  	{
  1310  		name:  "serverAuth EKU does not permit clientAuth",
  1311  		roots: make([]constraintsSpec, 1),
  1312  		intermediates: [][]constraintsSpec{
  1313  			{
  1314  				{},
  1315  			},
  1316  		},
  1317  		leaf: leafSpec{
  1318  			sans: []string{"dns:example.com"},
  1319  			ekus: []string{"serverAuth"},
  1320  		},
  1321  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
  1322  		expectedError: "incompatible key usage",
  1323  	},
  1324  	{
  1325  		name:  "msSGC EKU does not permit serverAuth",
  1326  		roots: make([]constraintsSpec, 1),
  1327  		intermediates: [][]constraintsSpec{
  1328  			{
  1329  				{},
  1330  			},
  1331  		},
  1332  		leaf: leafSpec{
  1333  			sans: []string{"dns:example.com"},
  1334  			ekus: []string{"msSGC"},
  1335  		},
  1336  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  1337  		expectedError: "incompatible key usage",
  1338  	},
  1339  	{
  1340  		// An invalid DNS SAN should be detected only at validation time so
  1341  		// that we can process CA certificates in the wild that have invalid SANs.
  1342  		// See https://github.com/golang/go/issues/23995
  1343  		name:  "invalid SANs are ignored with no constraints",
  1344  		roots: make([]constraintsSpec, 1),
  1345  		intermediates: [][]constraintsSpec{
  1346  			{
  1347  				{},
  1348  			},
  1349  		},
  1350  		leaf: leafSpec{
  1351  			sans: []string{"dns:this is invalid", "email:this @ is invalid"},
  1352  		},
  1353  	},
  1354  	{
  1355  		name: "invalid DNS SAN detected with constraints",
  1356  		roots: []constraintsSpec{
  1357  			{
  1358  				bad: []string{"uri:"},
  1359  			},
  1360  		},
  1361  		intermediates: [][]constraintsSpec{
  1362  			{
  1363  				{},
  1364  			},
  1365  		},
  1366  		leaf: leafSpec{
  1367  			sans: []string{"dns:this is invalid"},
  1368  		},
  1369  		expectedError: "cannot parse dnsName",
  1370  	},
  1371  	{
  1372  		name: "invalid email SAN detected with constraints",
  1373  		roots: []constraintsSpec{
  1374  			{
  1375  				bad: []string{"uri:"},
  1376  			},
  1377  		},
  1378  		intermediates: [][]constraintsSpec{
  1379  			{
  1380  				{},
  1381  			},
  1382  		},
  1383  		leaf: leafSpec{
  1384  			sans: []string{"email:this @ is invalid"},
  1385  		},
  1386  		expectedError: "cannot parse rfc822Name",
  1387  	},
  1388  	{
  1389  		name:  "any requested EKU is sufficient",
  1390  		roots: make([]constraintsSpec, 1),
  1391  		intermediates: [][]constraintsSpec{
  1392  			{
  1393  				{},
  1394  			},
  1395  		},
  1396  		leaf: leafSpec{
  1397  			sans: []string{"dns:example.com"},
  1398  			ekus: []string{"email"},
  1399  		},
  1400  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
  1401  	},
  1402  	{
  1403  		name:  "unrequested EKUs not required to be nested",
  1404  		roots: make([]constraintsSpec, 1),
  1405  		intermediates: [][]constraintsSpec{
  1406  			{
  1407  				{
  1408  					ekus: []string{"serverAuth"},
  1409  				},
  1410  			},
  1411  		},
  1412  		leaf: leafSpec{
  1413  			sans: []string{"dns:example.com"},
  1414  			// There's no email EKU in the intermediate. This would be rejected if
  1415  			// full nesting was required.
  1416  			ekus: []string{"email", "serverAuth"},
  1417  		},
  1418  	},
  1419  	{
  1420  		name: "empty leaf is accepted in constrained chain",
  1421  		roots: []constraintsSpec{
  1422  			{
  1423  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1424  			},
  1425  		},
  1426  		intermediates: [][]constraintsSpec{
  1427  			{
  1428  				{},
  1429  			},
  1430  		},
  1431  		leaf: leafSpec{
  1432  			sans: []string{},
  1433  		},
  1434  	},
  1435  	{
  1436  		name: "no SANs and non-hostname CN is accepted in constrained chain",
  1437  		roots: []constraintsSpec{
  1438  			{
  1439  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1440  			},
  1441  		},
  1442  		intermediates: [][]constraintsSpec{
  1443  			{
  1444  				{},
  1445  			},
  1446  		},
  1447  		leaf: leafSpec{
  1448  			sans: []string{},
  1449  			cn:   "foo.bar",
  1450  		},
  1451  	},
  1452  	{
  1453  		name: "constraints don't apply to CN",
  1454  		roots: []constraintsSpec{
  1455  			{
  1456  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1457  			},
  1458  		},
  1459  		intermediates: [][]constraintsSpec{
  1460  			{
  1461  				{},
  1462  			},
  1463  		},
  1464  		leaf: leafSpec{
  1465  			sans: []string{"dns:foo.com"},
  1466  			cn:   "foo.bar",
  1467  		},
  1468  	},
  1469  	{
  1470  		name:          "DNS SAN cannot use leading period form",
  1471  		roots:         []constraintsSpec{{ok: []string{"dns:example.com"}}},
  1472  		leaf:          leafSpec{sans: []string{"dns:.example.com"}},
  1473  		expectedError: "cannot parse dnsName \".example.com\"",
  1474  	},
  1475  	{
  1476  		name: "URI with IPv6 and zone is rejected",
  1477  		roots: []constraintsSpec{
  1478  			{
  1479  				ok: []string{"uri:example.com"},
  1480  			},
  1481  		},
  1482  		intermediates: [][]constraintsSpec{
  1483  			{
  1484  				{},
  1485  			},
  1486  		},
  1487  		leaf: leafSpec{
  1488  			sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
  1489  		},
  1490  		expectedError: "URI with IP",
  1491  	},
  1492  	{
  1493  		name: "intermediate can narrow permitted dns scope",
  1494  		roots: []constraintsSpec{
  1495  			{
  1496  				ok: []string{"dns:"},
  1497  			},
  1498  		},
  1499  		intermediates: [][]constraintsSpec{
  1500  			{
  1501  				{
  1502  					ok: []string{"dns:example.com"},
  1503  				},
  1504  			},
  1505  		},
  1506  		leaf: leafSpec{
  1507  			sans: []string{"dns:test.com"},
  1508  		},
  1509  		expectedError: "\"test.com\" is not permitted",
  1510  	},
  1511  	{
  1512  		name: "intermediate cannot narrow excluded dns scope",
  1513  		roots: []constraintsSpec{
  1514  			{
  1515  				bad: []string{"dns:"},
  1516  			},
  1517  		},
  1518  		intermediates: [][]constraintsSpec{
  1519  			{
  1520  				{
  1521  					bad: []string{"dns:example.com"},
  1522  				},
  1523  			},
  1524  		},
  1525  		leaf: leafSpec{
  1526  			sans: []string{"dns:test.com"},
  1527  		},
  1528  		expectedError: "\"test.com\" is excluded by constraint \"\"",
  1529  	},
  1530  	{
  1531  		name: "intermediate can narrow excluded dns scope",
  1532  		roots: []constraintsSpec{
  1533  			{
  1534  				bad: []string{"dns:example.com"},
  1535  			},
  1536  		},
  1537  		intermediates: [][]constraintsSpec{
  1538  			{
  1539  				{
  1540  					bad: []string{"dns:"},
  1541  				},
  1542  			},
  1543  		},
  1544  		leaf: leafSpec{
  1545  			sans: []string{"dns:test.com"},
  1546  		},
  1547  		expectedError: "\"test.com\" is excluded by constraint \"\"",
  1548  	},
  1549  	{
  1550  		name: "permitted dns constraint is not a prefix match",
  1551  		roots: []constraintsSpec{
  1552  			{
  1553  				ok: []string{"dns:example.com"},
  1554  			},
  1555  		},
  1556  		intermediates: [][]constraintsSpec{
  1557  			{
  1558  				{},
  1559  			},
  1560  		},
  1561  		leaf: leafSpec{
  1562  			sans: []string{"dns:testexample.com"},
  1563  		},
  1564  		expectedError: "\"testexample.com\" is not permitted",
  1565  	},
  1566  	{
  1567  		name: "subdomain constraint does not allow wildcard",
  1568  		roots: []constraintsSpec{
  1569  			{
  1570  				ok: []string{"dns:a.com", "dns:foo.example.com", "dns:z.com"},
  1571  			},
  1572  		},
  1573  		intermediates: [][]constraintsSpec{
  1574  			{
  1575  				{},
  1576  			},
  1577  		},
  1578  		leaf: leafSpec{
  1579  			sans: []string{"dns:*.example.com"},
  1580  		},
  1581  		expectedError: "\"*.example.com\" is not permitted",
  1582  	},
  1583  	{
  1584  		name: "excluded dns constraint is not a prefix match",
  1585  		roots: []constraintsSpec{
  1586  			{
  1587  				bad: []string{"dns:example.com"},
  1588  			},
  1589  		},
  1590  		intermediates: [][]constraintsSpec{
  1591  			{
  1592  				{},
  1593  			},
  1594  		},
  1595  		leaf: leafSpec{
  1596  			sans: []string{"dns:testexample.com"},
  1597  		},
  1598  	},
  1599  	{
  1600  		name: "excluded email constraint, multiple email with matching local portion",
  1601  		roots: []constraintsSpec{
  1602  			{
  1603  				bad: []string{"email:a@example.com", "email:a@test.com"},
  1604  			},
  1605  		},
  1606  		intermediates: [][]constraintsSpec{
  1607  			{
  1608  				{},
  1609  			},
  1610  		},
  1611  		leaf: leafSpec{
  1612  			sans: []string{"email:a@example.com"},
  1613  		},
  1614  		expectedError: "\"a@example.com\" is excluded by constraint \"a@example.com\"",
  1615  	},
  1616  	{
  1617  		name: "email_case_check",
  1618  		roots: []constraintsSpec{
  1619  			{
  1620  				ok: []string{"email:a@example.com"},
  1621  			},
  1622  		},
  1623  		intermediates: [][]constraintsSpec{
  1624  			{
  1625  				{},
  1626  			},
  1627  		},
  1628  		leaf: leafSpec{
  1629  			sans: []string{"email:a@ExAmple.com"},
  1630  		},
  1631  	},
  1632  	{
  1633  		name: "excluded constraint, empty DNS san",
  1634  		roots: []constraintsSpec{
  1635  			{
  1636  				bad: []string{"dns:example.com"},
  1637  			},
  1638  		},
  1639  		leaf: leafSpec{
  1640  			sans: []string{"dns:"},
  1641  		},
  1642  	},
  1643  
  1644  	{
  1645  		name: "subdomain excluded constraints preclude outer wildcard names",
  1646  		roots: []constraintsSpec{
  1647  			{
  1648  				bad: []string{"dns:foo.example.com"},
  1649  			},
  1650  		},
  1651  		intermediates: [][]constraintsSpec{
  1652  			{
  1653  				{},
  1654  			},
  1655  		},
  1656  		leaf: leafSpec{
  1657  			sans: []string{"dns:*.example.com"},
  1658  		},
  1659  		expectedError: "\"*.example.com\" is excluded by constraint \"foo.example.com\"",
  1660  	},
  1661  	{
  1662  		name: "subdomain excluded constraints do not preclude far outer wildcard names",
  1663  		roots: []constraintsSpec{
  1664  			{
  1665  				bad: []string{"dns:foo.example.com"},
  1666  			},
  1667  		},
  1668  		intermediates: [][]constraintsSpec{
  1669  			{
  1670  				{},
  1671  			},
  1672  		},
  1673  		leaf: leafSpec{
  1674  			sans: []string{"dns:*.com"},
  1675  		},
  1676  	},
  1677  	{
  1678  		name: "subdomain excluded constraints preclude inner wildcard names",
  1679  		roots: []constraintsSpec{
  1680  			{
  1681  				bad: []string{"dns:foo.example.com"},
  1682  			},
  1683  		},
  1684  		intermediates: [][]constraintsSpec{
  1685  			{
  1686  				{},
  1687  			},
  1688  		},
  1689  		leaf: leafSpec{
  1690  			sans: []string{"dns:*.foo.example.com"},
  1691  		},
  1692  		expectedError: "\"*.foo.example.com\" is excluded by constraint \"foo.example.com\"",
  1693  	},
  1694  	{
  1695  		name: "subdomain excluded constraints preclude far inner wildcard names",
  1696  		roots: []constraintsSpec{
  1697  			{
  1698  				bad: []string{"dns:foo.example.com"},
  1699  			},
  1700  		},
  1701  		intermediates: [][]constraintsSpec{
  1702  			{
  1703  				{},
  1704  			},
  1705  		},
  1706  		leaf: leafSpec{
  1707  			sans: []string{"dns:*.bar.foo.example.com"},
  1708  		},
  1709  		expectedError: "\"*.bar.foo.example.com\" is excluded by constraint \"foo.example.com\"",
  1710  	},
  1711  	{
  1712  		name: "outer wildcard names are not matched by subdomain permitted constraints",
  1713  		roots: []constraintsSpec{
  1714  			{
  1715  				ok: []string{"dns:foo.example.com"},
  1716  			},
  1717  		},
  1718  		intermediates: [][]constraintsSpec{
  1719  			{
  1720  				{},
  1721  			},
  1722  		},
  1723  		leaf: leafSpec{
  1724  			sans: []string{"dns:*.example.com"},
  1725  		},
  1726  		expectedError: "\"*.example.com\" is not permitted",
  1727  	},
  1728  	{
  1729  		name: "far outer wildcard names are not matched by subdomain permitted constraints",
  1730  		roots: []constraintsSpec{
  1731  			{
  1732  				ok: []string{"dns:foo.example.com"},
  1733  			},
  1734  		},
  1735  		intermediates: [][]constraintsSpec{
  1736  			{
  1737  				{},
  1738  			},
  1739  		},
  1740  		leaf: leafSpec{
  1741  			sans: []string{"dns:*.com"},
  1742  		},
  1743  		expectedError: "\"*.com\" is not permitted",
  1744  	},
  1745  	{
  1746  		name: "inner wildcard names are matched by subdomain permitted constraints",
  1747  		roots: []constraintsSpec{
  1748  			{
  1749  				ok: []string{"dns:foo.example.com"},
  1750  			},
  1751  		},
  1752  		intermediates: [][]constraintsSpec{
  1753  			{
  1754  				{},
  1755  			},
  1756  		},
  1757  		leaf: leafSpec{
  1758  			sans: []string{"dns:*.foo.example.com"},
  1759  		},
  1760  	},
  1761  	{
  1762  		name: "far inner wildcard names are matched by subdomain permitted constraints",
  1763  		roots: []constraintsSpec{
  1764  			{
  1765  				ok: []string{"dns:foo.example.com"},
  1766  			},
  1767  		},
  1768  		intermediates: [][]constraintsSpec{
  1769  			{
  1770  				{},
  1771  			},
  1772  		},
  1773  		leaf: leafSpec{
  1774  			sans: []string{"dns:*.bar.foo.example.com"},
  1775  		},
  1776  	},
  1777  
  1778  	{
  1779  		name: "cross include should not match",
  1780  		roots: []constraintsSpec{
  1781  			{
  1782  				ok: []string{"dns:foo.example.com"},
  1783  			},
  1784  		},
  1785  		intermediates: [][]constraintsSpec{
  1786  			{
  1787  				{},
  1788  			},
  1789  		},
  1790  		leaf: leafSpec{
  1791  			sans: []string{"dns:*.bar.example.com"},
  1792  		},
  1793  		expectedError: "\"*.bar.example.com\" is not permitted by any constraint",
  1794  	},
  1795  	{
  1796  		name: "cross exclude should not match",
  1797  		roots: []constraintsSpec{
  1798  			{
  1799  				bad: []string{"dns:foo.example.com"},
  1800  			},
  1801  		},
  1802  		intermediates: [][]constraintsSpec{
  1803  			{
  1804  				{},
  1805  			},
  1806  		},
  1807  		leaf: leafSpec{
  1808  			sans: []string{"dns:*.bar.example.com"},
  1809  		},
  1810  	},
  1811  	{
  1812  		name: "subdomain exclusion blocks uppercase wildcard",
  1813  		roots: []constraintsSpec{{
  1814  			bad: []string{"dns:sub.example.com"},
  1815  		}},
  1816  		intermediates: [][]constraintsSpec{{{}}},
  1817  		leaf: leafSpec{
  1818  			sans: []string{"dns:*.EXAMPLE.COM"},
  1819  		},
  1820  		expectedError: "\"*.EXAMPLE.COM\" is excluded by constraint \"sub.example.com\"",
  1821  	},
  1822  	{
  1823  		name: "uppercase subdomain exclusion blocks lowercase wildcard",
  1824  		roots: []constraintsSpec{{
  1825  			bad: []string{"dns:SUB.EXAMPLE.COM"},
  1826  		}},
  1827  		intermediates: [][]constraintsSpec{{{}}},
  1828  		leaf: leafSpec{
  1829  			sans: []string{"dns:*.example.com"},
  1830  		},
  1831  		expectedError: "\"*.example.com\" is excluded by constraint \"sub.example.com\"",
  1832  	},
  1833  }
  1834  
  1835  func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1836  	var serialBytes [16]byte
  1837  	rand.Read(serialBytes[:])
  1838  
  1839  	template := &Certificate{
  1840  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1841  		Subject: pkix.Name{
  1842  			CommonName: name,
  1843  		},
  1844  		NotBefore:             time.Unix(1000, 0),
  1845  		NotAfter:              time.Unix(2000, 0),
  1846  		KeyUsage:              KeyUsageCertSign,
  1847  		BasicConstraintsValid: true,
  1848  		IsCA:                  true,
  1849  	}
  1850  
  1851  	if err := addConstraintsToTemplate(constraints, template); err != nil {
  1852  		return nil, err
  1853  	}
  1854  
  1855  	if parent == nil {
  1856  		parent = template
  1857  	}
  1858  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1859  	if err != nil {
  1860  		return nil, err
  1861  	}
  1862  
  1863  	caCert, err := ParseCertificate(derBytes)
  1864  	if err != nil {
  1865  		return nil, err
  1866  	}
  1867  
  1868  	return caCert, nil
  1869  }
  1870  
  1871  func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1872  	var serialBytes [16]byte
  1873  	rand.Read(serialBytes[:])
  1874  
  1875  	template := &Certificate{
  1876  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1877  		Subject: pkix.Name{
  1878  			OrganizationalUnit: []string{"Leaf"},
  1879  			CommonName:         leaf.cn,
  1880  		},
  1881  		NotBefore:             time.Unix(1000, 0),
  1882  		NotAfter:              time.Unix(2000, 0),
  1883  		KeyUsage:              KeyUsageDigitalSignature,
  1884  		BasicConstraintsValid: true,
  1885  		IsCA:                  false,
  1886  	}
  1887  
  1888  	for _, name := range leaf.sans {
  1889  		switch {
  1890  		case strings.HasPrefix(name, "dns:"):
  1891  			template.DNSNames = append(template.DNSNames, name[4:])
  1892  
  1893  		case strings.HasPrefix(name, "ip:"):
  1894  			ip := net.ParseIP(name[3:])
  1895  			if ip == nil {
  1896  				return nil, fmt.Errorf("cannot parse IP %q", name[3:])
  1897  			}
  1898  			template.IPAddresses = append(template.IPAddresses, ip)
  1899  
  1900  		case strings.HasPrefix(name, "invalidip:"):
  1901  			ipBytes, err := hex.DecodeString(name[10:])
  1902  			if err != nil {
  1903  				return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
  1904  			}
  1905  			template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
  1906  
  1907  		case strings.HasPrefix(name, "email:"):
  1908  			template.EmailAddresses = append(template.EmailAddresses, name[6:])
  1909  
  1910  		case strings.HasPrefix(name, "uri:"):
  1911  			uri, err := url.Parse(name[4:])
  1912  			if err != nil {
  1913  				return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
  1914  			}
  1915  			template.URIs = append(template.URIs, uri)
  1916  
  1917  		case strings.HasPrefix(name, "unknown:"):
  1918  			// This is a special case for testing unknown
  1919  			// name types. A custom SAN extension is
  1920  			// injected into the certificate.
  1921  			if len(leaf.sans) != 1 {
  1922  				panic("when using unknown name types, it must be the sole name")
  1923  			}
  1924  
  1925  			template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
  1926  				Id: []int{2, 5, 29, 17},
  1927  				Value: []byte{
  1928  					0x30, // SEQUENCE
  1929  					3,    // three bytes
  1930  					9,    // undefined GeneralName type 9
  1931  					1,
  1932  					1,
  1933  				},
  1934  			})
  1935  
  1936  		default:
  1937  			return nil, fmt.Errorf("unknown name type %q", name)
  1938  		}
  1939  	}
  1940  
  1941  	var err error
  1942  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
  1943  		return nil, err
  1944  	}
  1945  
  1946  	if parent == nil {
  1947  		parent = template
  1948  	}
  1949  
  1950  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1951  	if err != nil {
  1952  		return nil, err
  1953  	}
  1954  
  1955  	return ParseCertificate(derBytes)
  1956  }
  1957  
  1958  func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
  1959  	appendConstraint := func(contents []byte, tag uint8) []byte {
  1960  		contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
  1961  		contents = append(contents, byte(4+len(constraint)) /* length */)
  1962  		contents = append(contents, 0x30 /* SEQUENCE */)
  1963  		contents = append(contents, byte(2+len(constraint)) /* length */)
  1964  		contents = append(contents, byte(typeNum) /* GeneralName type */)
  1965  		contents = append(contents, byte(len(constraint)))
  1966  		return append(contents, constraint...)
  1967  	}
  1968  
  1969  	var contents []byte
  1970  	if !isExcluded {
  1971  		contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
  1972  	} else {
  1973  		contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
  1974  	}
  1975  
  1976  	var value []byte
  1977  	value = append(value, 0x30 /* SEQUENCE */)
  1978  	value = append(value, byte(len(contents)))
  1979  	value = append(value, contents...)
  1980  
  1981  	return pkix.Extension{
  1982  		Id:    []int{2, 5, 29, 30},
  1983  		Value: value,
  1984  	}
  1985  }
  1986  
  1987  func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
  1988  	parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
  1989  		for _, constraint := range constraints {
  1990  			switch {
  1991  			case strings.HasPrefix(constraint, "dns:"):
  1992  				dnsNames = append(dnsNames, constraint[4:])
  1993  
  1994  			case strings.HasPrefix(constraint, "ip:"):
  1995  				_, ipNet, err := net.ParseCIDR(constraint[3:])
  1996  				if err != nil {
  1997  					return nil, nil, nil, nil, err
  1998  				}
  1999  				ips = append(ips, ipNet)
  2000  
  2001  			case strings.HasPrefix(constraint, "email:"):
  2002  				emailAddrs = append(emailAddrs, constraint[6:])
  2003  
  2004  			case strings.HasPrefix(constraint, "uri:"):
  2005  				uriDomains = append(uriDomains, constraint[4:])
  2006  
  2007  			default:
  2008  				return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
  2009  			}
  2010  		}
  2011  
  2012  		return dnsNames, ips, emailAddrs, uriDomains, err
  2013  	}
  2014  
  2015  	handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
  2016  		switch {
  2017  		case constraint == "unknown:":
  2018  			template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
  2019  
  2020  		default:
  2021  			return false
  2022  		}
  2023  
  2024  		return true
  2025  	}
  2026  
  2027  	if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
  2028  		if handleSpecialConstraint(constraints.ok[0], false) {
  2029  			return nil
  2030  		}
  2031  	}
  2032  
  2033  	if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
  2034  		if handleSpecialConstraint(constraints.bad[0], true) {
  2035  			return nil
  2036  		}
  2037  	}
  2038  
  2039  	var err error
  2040  	template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
  2041  	if err != nil {
  2042  		return err
  2043  	}
  2044  
  2045  	template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
  2046  	if err != nil {
  2047  		return err
  2048  	}
  2049  
  2050  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
  2051  		return err
  2052  	}
  2053  
  2054  	return nil
  2055  }
  2056  
  2057  func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
  2058  	for _, s := range ekuStrs {
  2059  		switch s {
  2060  		case "serverAuth":
  2061  			ekus = append(ekus, ExtKeyUsageServerAuth)
  2062  		case "clientAuth":
  2063  			ekus = append(ekus, ExtKeyUsageClientAuth)
  2064  		case "email":
  2065  			ekus = append(ekus, ExtKeyUsageEmailProtection)
  2066  		case "netscapeSGC":
  2067  			ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
  2068  		case "msSGC":
  2069  			ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
  2070  		case "any":
  2071  			ekus = append(ekus, ExtKeyUsageAny)
  2072  		case "other":
  2073  			unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
  2074  		default:
  2075  			return nil, nil, fmt.Errorf("unknown EKU %q", s)
  2076  		}
  2077  	}
  2078  
  2079  	return
  2080  }
  2081  
  2082  func TestConstraintCases(t *testing.T) {
  2083  	privateKeys := sync.Pool{
  2084  		New: func() any {
  2085  			priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2086  			if err != nil {
  2087  				panic(err)
  2088  			}
  2089  			return priv
  2090  		},
  2091  	}
  2092  
  2093  	for i, test := range nameConstraintsTests {
  2094  		t.Run(test.name, func(t *testing.T) {
  2095  			rootPool := NewCertPool()
  2096  			rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
  2097  			rootName := "Root " + strconv.Itoa(i)
  2098  
  2099  			// keys keeps track of all the private keys used in a given
  2100  			// test and puts them back in the privateKeys pool at the end.
  2101  			keys := []*ecdsa.PrivateKey{rootKey}
  2102  
  2103  			// At each level (root, intermediate(s), leaf), parent points to
  2104  			// an example parent certificate and parentKey the key for the
  2105  			// parent level. Since all certificates at a given level have
  2106  			// the same name and public key, any parent certificate is
  2107  			// sufficient to get the correct issuer name and authority
  2108  			// key ID.
  2109  			var parent *Certificate
  2110  			parentKey := rootKey
  2111  
  2112  			for _, root := range test.roots {
  2113  				rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
  2114  				if err != nil {
  2115  					t.Fatalf("failed to create root: %s", err)
  2116  				}
  2117  
  2118  				parent = rootCert
  2119  				rootPool.AddCert(rootCert)
  2120  			}
  2121  
  2122  			intermediatePool := NewCertPool()
  2123  
  2124  			for level, intermediates := range test.intermediates {
  2125  				levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
  2126  				keys = append(keys, levelKey)
  2127  				levelName := "Intermediate level " + strconv.Itoa(level)
  2128  				var last *Certificate
  2129  
  2130  				for _, intermediate := range intermediates {
  2131  					caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
  2132  					if err != nil {
  2133  						t.Fatalf("failed to create %q: %s", levelName, err)
  2134  					}
  2135  
  2136  					last = caCert
  2137  					intermediatePool.AddCert(caCert)
  2138  				}
  2139  
  2140  				parent = last
  2141  				parentKey = levelKey
  2142  			}
  2143  
  2144  			leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
  2145  			keys = append(keys, leafKey)
  2146  
  2147  			leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
  2148  			if err != nil {
  2149  				t.Fatalf("cannot create leaf: %s", err)
  2150  			}
  2151  
  2152  			// Skip tests with CommonName set because OpenSSL will try to match it
  2153  			// against name constraints, while we ignore it when it's not hostname-looking.
  2154  			if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
  2155  				output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
  2156  				if err == nil && len(test.expectedError) > 0 {
  2157  					t.Error("unexpectedly succeeded against OpenSSL")
  2158  					if debugOpenSSLFailure {
  2159  						return
  2160  					}
  2161  				}
  2162  
  2163  				if err != nil {
  2164  					if _, ok := err.(*exec.ExitError); !ok {
  2165  						t.Errorf("OpenSSL failed to run: %s", err)
  2166  					} else if len(test.expectedError) == 0 {
  2167  						t.Errorf("OpenSSL unexpectedly failed: %v", output)
  2168  						if debugOpenSSLFailure {
  2169  							return
  2170  						}
  2171  					}
  2172  				}
  2173  			}
  2174  
  2175  			verifyOpts := VerifyOptions{
  2176  				Roots:         rootPool,
  2177  				Intermediates: intermediatePool,
  2178  				CurrentTime:   time.Unix(1500, 0),
  2179  				KeyUsages:     test.requestedEKUs,
  2180  			}
  2181  			_, err = leafCert.Verify(verifyOpts)
  2182  
  2183  			logInfo := false
  2184  			if len(test.expectedError) == 0 {
  2185  				if err != nil {
  2186  					t.Errorf("unexpected failure: %s", err)
  2187  				} else {
  2188  					logInfo = false
  2189  				}
  2190  			} else {
  2191  				if err == nil {
  2192  					t.Error("unexpected success")
  2193  				} else if !strings.Contains(err.Error(), test.expectedError) {
  2194  					t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
  2195  				} else {
  2196  					logInfo = false
  2197  				}
  2198  			}
  2199  
  2200  			if logInfo {
  2201  				certAsPEM := func(cert *Certificate) string {
  2202  					var buf bytes.Buffer
  2203  					pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
  2204  					return buf.String()
  2205  				}
  2206  				t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
  2207  				if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
  2208  					for ii, intermediate := range intermediates {
  2209  						t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
  2210  					}
  2211  				}
  2212  				t.Errorf("leaf:\n%s", certAsPEM(leafCert))
  2213  			}
  2214  
  2215  			for _, key := range keys {
  2216  				privateKeys.Put(key)
  2217  			}
  2218  		})
  2219  	}
  2220  }
  2221  
  2222  func TestNameConstraintIPNonZeroHostBits(t *testing.T) {
  2223  	rootKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2224  	if err != nil {
  2225  		t.Fatal(err)
  2226  	}
  2227  	leafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2228  	if err != nil {
  2229  		t.Fatal(err)
  2230  	}
  2231  
  2232  	// Two excluded iPAddress subtrees: a lower-addressed range that takes the
  2233  	// binary-search neighbor slot, and one whose address has host bits set
  2234  	// (10.10.10.10/16, i.e. network 10.10.0.0/16).
  2235  	subtree := func(b ...byte) []byte {
  2236  		gn := append([]byte{0x87, byte(len(b))}, b...)
  2237  		return append([]byte{0x30, byte(len(gn))}, gn...)
  2238  	}
  2239  	var subtrees []byte
  2240  	subtrees = append(subtrees, subtree(10, 0, 0, 0, 255, 255, 255, 252)...)
  2241  	subtrees = append(subtrees, subtree(10, 10, 10, 10, 255, 255, 0, 0)...)
  2242  	excluded := append([]byte{0xa1, byte(len(subtrees))}, subtrees...)
  2243  	ncValue := append([]byte{0x30, byte(len(excluded))}, excluded...)
  2244  
  2245  	var serial [16]byte
  2246  	rand.Read(serial[:])
  2247  	rootTmpl := &Certificate{
  2248  		SerialNumber:          new(big.Int).SetBytes(serial[:]),
  2249  		Subject:               pkix.Name{CommonName: "Root"},
  2250  		NotBefore:             time.Unix(1000, 0),
  2251  		NotAfter:              time.Unix(2000, 0),
  2252  		KeyUsage:              KeyUsageCertSign,
  2253  		BasicConstraintsValid: true,
  2254  		IsCA:                  true,
  2255  		ExtraExtensions: []pkix.Extension{
  2256  			{Id: []int{2, 5, 29, 30}, Critical: true, Value: ncValue},
  2257  		},
  2258  	}
  2259  	rootDER, err := CreateCertificate(rand.Reader, rootTmpl, rootTmpl, &rootKey.PublicKey, rootKey)
  2260  	if err != nil {
  2261  		t.Fatal(err)
  2262  	}
  2263  	root, err := ParseCertificate(rootDER)
  2264  	if err != nil {
  2265  		t.Fatal(err)
  2266  	}
  2267  
  2268  	// The parsed range must keep the address as encoded, host bits and all.
  2269  	if len(root.ExcludedIPRanges) != 2 {
  2270  		t.Fatalf("got %d excluded IP ranges, want 2", len(root.ExcludedIPRanges))
  2271  	}
  2272  	if got := root.ExcludedIPRanges[1].IP; !got.Equal(net.IP{10, 10, 10, 10}) {
  2273  		t.Errorf("excluded range IP = %v, want 10.10.10.10", got)
  2274  	}
  2275  
  2276  	leaf, err := makeConstraintsLeafCert(leafSpec{sans: []string{"ip:10.10.0.1"}}, leafKey, root, rootKey)
  2277  	if err != nil {
  2278  		t.Fatal(err)
  2279  	}
  2280  
  2281  	roots := NewCertPool()
  2282  	roots.AddCert(root)
  2283  	if _, err := leaf.Verify(VerifyOptions{Roots: roots, CurrentTime: time.Unix(1500, 0)}); err == nil {
  2284  		t.Error("leaf with IP SAN inside excluded range was accepted")
  2285  	} else if !strings.Contains(err.Error(), "excluded by constraint") {
  2286  		t.Errorf("got error %q, want excluded-by-constraint", err)
  2287  	}
  2288  }
  2289  
  2290  func writePEMsToTempFile(certs []*Certificate) *os.File {
  2291  	file, err := os.CreateTemp("", "name_constraints_test")
  2292  	if err != nil {
  2293  		panic("cannot create tempfile")
  2294  	}
  2295  
  2296  	pemBlock := &pem.Block{Type: "CERTIFICATE"}
  2297  	for _, cert := range certs {
  2298  		pemBlock.Bytes = cert.Raw
  2299  		pem.Encode(file, pemBlock)
  2300  	}
  2301  
  2302  	return file
  2303  }
  2304  
  2305  func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
  2306  	args := []string{"verify", "-no_check_time"}
  2307  
  2308  	rootsFile := writePEMsToTempFile(allCerts(t, roots))
  2309  	if debugOpenSSLFailure {
  2310  		println("roots file:", rootsFile.Name())
  2311  	} else {
  2312  		defer os.Remove(rootsFile.Name())
  2313  	}
  2314  	args = append(args, "-CAfile", rootsFile.Name())
  2315  
  2316  	if intermediates.len() > 0 {
  2317  		intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
  2318  		if debugOpenSSLFailure {
  2319  			println("intermediates file:", intermediatesFile.Name())
  2320  		} else {
  2321  			defer os.Remove(intermediatesFile.Name())
  2322  		}
  2323  		args = append(args, "-untrusted", intermediatesFile.Name())
  2324  	}
  2325  
  2326  	leafFile := writePEMsToTempFile([]*Certificate{leaf})
  2327  	if debugOpenSSLFailure {
  2328  		println("leaf file:", leafFile.Name())
  2329  	} else {
  2330  		defer os.Remove(leafFile.Name())
  2331  	}
  2332  	args = append(args, leafFile.Name())
  2333  
  2334  	cmd := testenv.Command(t, "openssl", args...)
  2335  	out, err := cmd.CombinedOutput()
  2336  	return string(out), err
  2337  }
  2338  
  2339  var rfc2821Tests = []struct {
  2340  	in                string
  2341  	localPart, domain string
  2342  }{
  2343  	{"foo@example.com", "foo", "example.com"},
  2344  	{"@example.com", "", ""},
  2345  	{"\"@example.com", "", ""},
  2346  	{"\"\"@example.com", "", "example.com"},
  2347  	{"\"a\"@example.com", "a", "example.com"},
  2348  	{"\"\\a\"@example.com", "a", "example.com"},
  2349  	{"a\"@example.com", "", ""},
  2350  	{"foo..bar@example.com", "", ""},
  2351  	{".foo.bar@example.com", "", ""},
  2352  	{"foo.bar.@example.com", "", ""},
  2353  	{"|{}?'@example.com", "|{}?'", "example.com"},
  2354  	{"a@b@c.com", "", ""},
  2355  
  2356  	// Examples from RFC 3696
  2357  	{"Abc\\@def@example.com", "Abc@def", "example.com"},
  2358  	{"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
  2359  	{"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
  2360  	{"\"Abc@def\"@example.com", "Abc@def", "example.com"},
  2361  	{"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
  2362  	{"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
  2363  	{"$A12345@example.com", "$A12345", "example.com"},
  2364  	{"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
  2365  	{"_somename@example.com", "_somename", "example.com"},
  2366  }
  2367  
  2368  func TestRFC2821Parsing(t *testing.T) {
  2369  	for i, test := range rfc2821Tests {
  2370  		mailbox, ok := parseRFC2821Mailbox(test.in)
  2371  		expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
  2372  
  2373  		if ok && expectedFailure {
  2374  			t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
  2375  			continue
  2376  		}
  2377  
  2378  		if !ok && !expectedFailure {
  2379  			t.Errorf("#%d: unexpected failure for %q", i, test.in)
  2380  			continue
  2381  		}
  2382  
  2383  		if !ok {
  2384  			continue
  2385  		}
  2386  
  2387  		if mailbox.local != test.localPart || mailbox.domain != test.domain {
  2388  			t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
  2389  		}
  2390  	}
  2391  }
  2392  
  2393  func TestBadNamesInConstraints(t *testing.T) {
  2394  	constraintParseError := func(err error) bool {
  2395  		str := err.Error()
  2396  		return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
  2397  	}
  2398  
  2399  	encodingError := func(err error) bool {
  2400  		return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
  2401  	}
  2402  
  2403  	// Bad names in constraints should not parse.
  2404  	badNames := []struct {
  2405  		name    string
  2406  		matcher func(error) bool
  2407  	}{
  2408  		{"dns:foo.com.", constraintParseError},
  2409  		{"email:abc@foo.com.", constraintParseError},
  2410  		{"email:foo.com.", constraintParseError},
  2411  		{"uri:example.com.", constraintParseError},
  2412  		{"uri:1.2.3.4", constraintParseError},
  2413  		{"uri:ffff::1", constraintParseError},
  2414  		{"dns:not–hyphen.com", encodingError},
  2415  		{"email:foo@not–hyphen.com", encodingError},
  2416  		{"uri:not–hyphen.com", encodingError},
  2417  	}
  2418  
  2419  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2420  	if err != nil {
  2421  		panic(err)
  2422  	}
  2423  
  2424  	for _, test := range badNames {
  2425  		_, err := makeConstraintsCACert(constraintsSpec{
  2426  			ok: []string{test.name},
  2427  		}, "TestAbsoluteNamesInConstraints", priv, nil, priv)
  2428  
  2429  		if err == nil {
  2430  			t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
  2431  			continue
  2432  		} else {
  2433  			if !test.matcher(err) {
  2434  				t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
  2435  			}
  2436  		}
  2437  	}
  2438  }
  2439  
  2440  func TestBadNamesInSANs(t *testing.T) {
  2441  	// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
  2442  	// will parse and are tested in name constraint tests at the top of this
  2443  	// file.
  2444  	badNames := []string{
  2445  		"uri:https://example.com./dsf",
  2446  		"invalidip:0102",
  2447  		"invalidip:0102030405",
  2448  	}
  2449  
  2450  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2451  	if err != nil {
  2452  		panic(err)
  2453  	}
  2454  
  2455  	for _, badName := range badNames {
  2456  		_, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
  2457  
  2458  		if err == nil {
  2459  			t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
  2460  			continue
  2461  		}
  2462  
  2463  		if str := err.Error(); !strings.Contains(str, "cannot parse ") {
  2464  			t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
  2465  		}
  2466  	}
  2467  }
  2468  

View as plain text