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: "IPv4-mapped-IPv6 exclusion does not affect IPv4",
  1043  		roots: []constraintsSpec{
  1044  			{
  1045  				bad: []string{"ip:::ffff:1.2.3.4/128"},
  1046  			},
  1047  		},
  1048  		intermediates: [][]constraintsSpec{
  1049  			{
  1050  				{},
  1051  			},
  1052  		},
  1053  		leaf: leafSpec{
  1054  			sans: []string{"ip:1.2.3.4"},
  1055  		},
  1056  	},
  1057  	{
  1058  		name: "URI constraint not matched by URN",
  1059  		roots: []constraintsSpec{
  1060  			{
  1061  				ok: []string{"uri:example.com"},
  1062  			},
  1063  		},
  1064  		intermediates: [][]constraintsSpec{
  1065  			{
  1066  				{},
  1067  			},
  1068  		},
  1069  		leaf: leafSpec{
  1070  			sans: []string{"uri:urn:example"},
  1071  		},
  1072  		expectedError: "URI with empty host",
  1073  	},
  1074  	{
  1075  		name: "IPv6 exclusion does not exclude all IPv4",
  1076  		roots: []constraintsSpec{
  1077  			{
  1078  				ok:  []string{"ip:1.2.3.0/24"},
  1079  				bad: []string{"ip:::0/0"},
  1080  			},
  1081  		},
  1082  		intermediates: [][]constraintsSpec{
  1083  			{
  1084  				{},
  1085  			},
  1086  		},
  1087  		leaf: leafSpec{
  1088  			sans: []string{"ip:1.2.3.4"},
  1089  		},
  1090  	},
  1091  	{
  1092  		name:  "empty EKU in CA means any is ok",
  1093  		roots: make([]constraintsSpec, 1),
  1094  		intermediates: [][]constraintsSpec{
  1095  			{
  1096  				{},
  1097  			},
  1098  		},
  1099  		leaf: leafSpec{
  1100  			sans: []string{"dns:example.com"},
  1101  			ekus: []string{"serverAuth", "other"},
  1102  		},
  1103  	},
  1104  	{
  1105  		name:  "any EKU means any is ok",
  1106  		roots: make([]constraintsSpec, 1),
  1107  		intermediates: [][]constraintsSpec{
  1108  			{
  1109  				{
  1110  					ekus: []string{"any"},
  1111  				},
  1112  			},
  1113  		},
  1114  		leaf: leafSpec{
  1115  			sans: []string{"dns:example.com"},
  1116  			ekus: []string{"serverAuth", "other"},
  1117  		},
  1118  	},
  1119  	// default.)
  1120  	{
  1121  		name:  "intermediate with enumerated EKUs",
  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{"serverAuth"},
  1133  		},
  1134  		expectedError: "incompatible key usage",
  1135  	},
  1136  	{
  1137  		name:  "unknown EKU in leaf",
  1138  		roots: make([]constraintsSpec, 1),
  1139  		intermediates: [][]constraintsSpec{
  1140  			{
  1141  				{
  1142  					ekus: []string{"email"},
  1143  				},
  1144  			},
  1145  		},
  1146  		leaf: leafSpec{
  1147  			sans: []string{"dns:example.com"},
  1148  			ekus: []string{"other"},
  1149  		},
  1150  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
  1151  	},
  1152  	// certificate doesn't use them.
  1153  	{
  1154  		name: "intermediate cannot add EKUs not in root if leaf uses them",
  1155  		roots: []constraintsSpec{
  1156  			{
  1157  				ekus: []string{"serverAuth"},
  1158  			},
  1159  		},
  1160  		intermediates: [][]constraintsSpec{
  1161  			{
  1162  				{
  1163  					ekus: []string{"serverAuth", "email"},
  1164  				},
  1165  			},
  1166  		},
  1167  		leaf: leafSpec{
  1168  			sans: []string{"dns:example.com"},
  1169  			ekus: []string{"serverAuth"},
  1170  		},
  1171  	},
  1172  	{
  1173  		name: "EKUs in root are effective",
  1174  		roots: []constraintsSpec{
  1175  			{
  1176  				ekus: []string{"email"},
  1177  			},
  1178  		},
  1179  		intermediates: [][]constraintsSpec{
  1180  			{
  1181  				{
  1182  					ekus: []string{"serverAuth"},
  1183  				},
  1184  			},
  1185  		},
  1186  		leaf: leafSpec{
  1187  			sans: []string{"dns:example.com"},
  1188  			ekus: []string{"serverAuth"},
  1189  		},
  1190  		expectedError: "incompatible key usage",
  1191  	},
  1192  	{
  1193  		name: "netscapeSGC EKU does not permit server/client auth",
  1194  		roots: []constraintsSpec{
  1195  			{},
  1196  		},
  1197  		intermediates: [][]constraintsSpec{
  1198  			{
  1199  				{
  1200  					ekus: []string{"netscapeSGC"},
  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:  "msSGC EKU does not permit server/client auth",
  1212  		roots: make([]constraintsSpec, 1),
  1213  		intermediates: [][]constraintsSpec{
  1214  			{
  1215  				{
  1216  					ekus: []string{"msSGC"},
  1217  				},
  1218  			},
  1219  		},
  1220  		leaf: leafSpec{
  1221  			sans: []string{"dns:example.com"},
  1222  			ekus: []string{"serverAuth", "clientAuth"},
  1223  		},
  1224  		expectedError: "incompatible key usage",
  1225  	},
  1226  	{
  1227  		name: "empty DNS permitted constraint allows anything",
  1228  		roots: []constraintsSpec{
  1229  			{
  1230  				ok: []string{"dns:"},
  1231  			},
  1232  		},
  1233  		intermediates: [][]constraintsSpec{
  1234  			{
  1235  				{},
  1236  			},
  1237  		},
  1238  		leaf: leafSpec{
  1239  			sans: []string{"dns:example.com"},
  1240  		},
  1241  	},
  1242  	{
  1243  		name: "empty DNS excluded constraint rejects everything",
  1244  		roots: []constraintsSpec{
  1245  			{
  1246  				bad: []string{"dns:"},
  1247  			},
  1248  		},
  1249  		intermediates: [][]constraintsSpec{
  1250  			{
  1251  				{},
  1252  			},
  1253  		},
  1254  		leaf: leafSpec{
  1255  			sans: []string{"dns:example.com"},
  1256  		},
  1257  		expectedError: "\"example.com\" is excluded",
  1258  	},
  1259  	{
  1260  		name: "empty email permitted constraint allows anything",
  1261  		roots: []constraintsSpec{
  1262  			{
  1263  				ok: []string{"email:"},
  1264  			},
  1265  		},
  1266  		intermediates: [][]constraintsSpec{
  1267  			{
  1268  				{},
  1269  			},
  1270  		},
  1271  		leaf: leafSpec{
  1272  			sans: []string{"email:foo@example.com"},
  1273  		},
  1274  	},
  1275  	{
  1276  		name: "empty email excluded constraint rejects everything",
  1277  		roots: []constraintsSpec{
  1278  			{
  1279  				bad: []string{"email:"},
  1280  			},
  1281  		},
  1282  		intermediates: [][]constraintsSpec{
  1283  			{
  1284  				{},
  1285  			},
  1286  		},
  1287  		leaf: leafSpec{
  1288  			sans: []string{"email:foo@example.com"},
  1289  		},
  1290  		expectedError: "\"foo@example.com\" is excluded",
  1291  	},
  1292  	{
  1293  		name: "empty URI permitted constraint allows anything",
  1294  		roots: []constraintsSpec{
  1295  			{
  1296  				ok: []string{"uri:"},
  1297  			},
  1298  		},
  1299  		intermediates: [][]constraintsSpec{
  1300  			{
  1301  				{},
  1302  			},
  1303  		},
  1304  		leaf: leafSpec{
  1305  			sans: []string{"uri:https://example.com/test"},
  1306  		},
  1307  	},
  1308  	{
  1309  		name: "empty URI excluded constraint rejects everything",
  1310  		roots: []constraintsSpec{
  1311  			{
  1312  				bad: []string{"uri:"},
  1313  			},
  1314  		},
  1315  		intermediates: [][]constraintsSpec{
  1316  			{
  1317  				{},
  1318  			},
  1319  		},
  1320  		leaf: leafSpec{
  1321  			sans: []string{"uri:https://example.com/test"},
  1322  		},
  1323  		expectedError: "\"https://example.com/test\" is excluded",
  1324  	},
  1325  	{
  1326  		name:  "serverAuth EKU does not permit clientAuth",
  1327  		roots: make([]constraintsSpec, 1),
  1328  		intermediates: [][]constraintsSpec{
  1329  			{
  1330  				{},
  1331  			},
  1332  		},
  1333  		leaf: leafSpec{
  1334  			sans: []string{"dns:example.com"},
  1335  			ekus: []string{"serverAuth"},
  1336  		},
  1337  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
  1338  		expectedError: "incompatible key usage",
  1339  	},
  1340  	{
  1341  		name:  "msSGC EKU does not permit serverAuth",
  1342  		roots: make([]constraintsSpec, 1),
  1343  		intermediates: [][]constraintsSpec{
  1344  			{
  1345  				{},
  1346  			},
  1347  		},
  1348  		leaf: leafSpec{
  1349  			sans: []string{"dns:example.com"},
  1350  			ekus: []string{"msSGC"},
  1351  		},
  1352  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  1353  		expectedError: "incompatible key usage",
  1354  	},
  1355  	{
  1356  		// An invalid DNS SAN should be detected only at validation time so
  1357  		// that we can process CA certificates in the wild that have invalid SANs.
  1358  		// See https://github.com/golang/go/issues/23995
  1359  		name:  "invalid SANs are ignored with no constraints",
  1360  		roots: make([]constraintsSpec, 1),
  1361  		intermediates: [][]constraintsSpec{
  1362  			{
  1363  				{},
  1364  			},
  1365  		},
  1366  		leaf: leafSpec{
  1367  			sans: []string{"dns:this is invalid", "email:this @ is invalid"},
  1368  		},
  1369  	},
  1370  	{
  1371  		name: "invalid DNS SAN detected with constraints",
  1372  		roots: []constraintsSpec{
  1373  			{
  1374  				bad: []string{"uri:"},
  1375  			},
  1376  		},
  1377  		intermediates: [][]constraintsSpec{
  1378  			{
  1379  				{},
  1380  			},
  1381  		},
  1382  		leaf: leafSpec{
  1383  			sans: []string{"dns:this is invalid"},
  1384  		},
  1385  		expectedError: "cannot parse dnsName",
  1386  	},
  1387  	{
  1388  		name: "invalid email SAN detected with constraints",
  1389  		roots: []constraintsSpec{
  1390  			{
  1391  				bad: []string{"uri:"},
  1392  			},
  1393  		},
  1394  		intermediates: [][]constraintsSpec{
  1395  			{
  1396  				{},
  1397  			},
  1398  		},
  1399  		leaf: leafSpec{
  1400  			sans: []string{"email:this @ is invalid"},
  1401  		},
  1402  		expectedError: "cannot parse rfc822Name",
  1403  	},
  1404  	{
  1405  		name:  "any requested EKU is sufficient",
  1406  		roots: make([]constraintsSpec, 1),
  1407  		intermediates: [][]constraintsSpec{
  1408  			{
  1409  				{},
  1410  			},
  1411  		},
  1412  		leaf: leafSpec{
  1413  			sans: []string{"dns:example.com"},
  1414  			ekus: []string{"email"},
  1415  		},
  1416  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
  1417  	},
  1418  	{
  1419  		name:  "unrequested EKUs not required to be nested",
  1420  		roots: make([]constraintsSpec, 1),
  1421  		intermediates: [][]constraintsSpec{
  1422  			{
  1423  				{
  1424  					ekus: []string{"serverAuth"},
  1425  				},
  1426  			},
  1427  		},
  1428  		leaf: leafSpec{
  1429  			sans: []string{"dns:example.com"},
  1430  			// There's no email EKU in the intermediate. This would be rejected if
  1431  			// full nesting was required.
  1432  			ekus: []string{"email", "serverAuth"},
  1433  		},
  1434  	},
  1435  	{
  1436  		name: "empty leaf 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  		},
  1450  	},
  1451  	{
  1452  		name: "no SANs and non-hostname CN is accepted in constrained chain",
  1453  		roots: []constraintsSpec{
  1454  			{
  1455  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1456  			},
  1457  		},
  1458  		intermediates: [][]constraintsSpec{
  1459  			{
  1460  				{},
  1461  			},
  1462  		},
  1463  		leaf: leafSpec{
  1464  			sans: []string{},
  1465  			cn:   "foo.bar",
  1466  		},
  1467  	},
  1468  	{
  1469  		name: "constraints don't apply to CN",
  1470  		roots: []constraintsSpec{
  1471  			{
  1472  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1473  			},
  1474  		},
  1475  		intermediates: [][]constraintsSpec{
  1476  			{
  1477  				{},
  1478  			},
  1479  		},
  1480  		leaf: leafSpec{
  1481  			sans: []string{"dns:foo.com"},
  1482  			cn:   "foo.bar",
  1483  		},
  1484  	},
  1485  	{
  1486  		name:          "DNS SAN cannot use leading period form",
  1487  		roots:         []constraintsSpec{{ok: []string{"dns:example.com"}}},
  1488  		leaf:          leafSpec{sans: []string{"dns:.example.com"}},
  1489  		expectedError: "cannot parse dnsName \".example.com\"",
  1490  	},
  1491  	{
  1492  		name: "URI with IPv6 and zone is rejected",
  1493  		roots: []constraintsSpec{
  1494  			{
  1495  				ok: []string{"uri:example.com"},
  1496  			},
  1497  		},
  1498  		intermediates: [][]constraintsSpec{
  1499  			{
  1500  				{},
  1501  			},
  1502  		},
  1503  		leaf: leafSpec{
  1504  			sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
  1505  		},
  1506  		expectedError: "URI with IP",
  1507  	},
  1508  	{
  1509  		name: "intermediate can narrow permitted dns scope",
  1510  		roots: []constraintsSpec{
  1511  			{
  1512  				ok: []string{"dns:"},
  1513  			},
  1514  		},
  1515  		intermediates: [][]constraintsSpec{
  1516  			{
  1517  				{
  1518  					ok: []string{"dns:example.com"},
  1519  				},
  1520  			},
  1521  		},
  1522  		leaf: leafSpec{
  1523  			sans: []string{"dns:test.com"},
  1524  		},
  1525  		expectedError: "\"test.com\" is not permitted",
  1526  	},
  1527  	{
  1528  		name: "intermediate cannot narrow excluded dns scope",
  1529  		roots: []constraintsSpec{
  1530  			{
  1531  				bad: []string{"dns:"},
  1532  			},
  1533  		},
  1534  		intermediates: [][]constraintsSpec{
  1535  			{
  1536  				{
  1537  					bad: []string{"dns:example.com"},
  1538  				},
  1539  			},
  1540  		},
  1541  		leaf: leafSpec{
  1542  			sans: []string{"dns:test.com"},
  1543  		},
  1544  		expectedError: "\"test.com\" is excluded by constraint \"\"",
  1545  	},
  1546  	{
  1547  		name: "intermediate can narrow excluded dns scope",
  1548  		roots: []constraintsSpec{
  1549  			{
  1550  				bad: []string{"dns:example.com"},
  1551  			},
  1552  		},
  1553  		intermediates: [][]constraintsSpec{
  1554  			{
  1555  				{
  1556  					bad: []string{"dns:"},
  1557  				},
  1558  			},
  1559  		},
  1560  		leaf: leafSpec{
  1561  			sans: []string{"dns:test.com"},
  1562  		},
  1563  		expectedError: "\"test.com\" is excluded by constraint \"\"",
  1564  	},
  1565  	{
  1566  		name: "permitted dns constraint is not a prefix match",
  1567  		roots: []constraintsSpec{
  1568  			{
  1569  				ok: []string{"dns:example.com"},
  1570  			},
  1571  		},
  1572  		intermediates: [][]constraintsSpec{
  1573  			{
  1574  				{},
  1575  			},
  1576  		},
  1577  		leaf: leafSpec{
  1578  			sans: []string{"dns:testexample.com"},
  1579  		},
  1580  		expectedError: "\"testexample.com\" is not permitted",
  1581  	},
  1582  	{
  1583  		name: "subdomain constraint does not allow wildcard",
  1584  		roots: []constraintsSpec{
  1585  			{
  1586  				ok: []string{"dns:a.com", "dns:foo.example.com", "dns:z.com"},
  1587  			},
  1588  		},
  1589  		intermediates: [][]constraintsSpec{
  1590  			{
  1591  				{},
  1592  			},
  1593  		},
  1594  		leaf: leafSpec{
  1595  			sans: []string{"dns:*.example.com"},
  1596  		},
  1597  		expectedError: "\"*.example.com\" is not permitted",
  1598  	},
  1599  	{
  1600  		name: "excluded dns constraint is not a prefix match",
  1601  		roots: []constraintsSpec{
  1602  			{
  1603  				bad: []string{"dns:example.com"},
  1604  			},
  1605  		},
  1606  		intermediates: [][]constraintsSpec{
  1607  			{
  1608  				{},
  1609  			},
  1610  		},
  1611  		leaf: leafSpec{
  1612  			sans: []string{"dns:testexample.com"},
  1613  		},
  1614  	},
  1615  }
  1616  
  1617  func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1618  	var serialBytes [16]byte
  1619  	rand.Read(serialBytes[:])
  1620  
  1621  	template := &Certificate{
  1622  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1623  		Subject: pkix.Name{
  1624  			CommonName: name,
  1625  		},
  1626  		NotBefore:             time.Unix(1000, 0),
  1627  		NotAfter:              time.Unix(2000, 0),
  1628  		KeyUsage:              KeyUsageCertSign,
  1629  		BasicConstraintsValid: true,
  1630  		IsCA:                  true,
  1631  	}
  1632  
  1633  	if err := addConstraintsToTemplate(constraints, template); err != nil {
  1634  		return nil, err
  1635  	}
  1636  
  1637  	if parent == nil {
  1638  		parent = template
  1639  	}
  1640  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1641  	if err != nil {
  1642  		return nil, err
  1643  	}
  1644  
  1645  	caCert, err := ParseCertificate(derBytes)
  1646  	if err != nil {
  1647  		return nil, err
  1648  	}
  1649  
  1650  	return caCert, nil
  1651  }
  1652  
  1653  func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1654  	var serialBytes [16]byte
  1655  	rand.Read(serialBytes[:])
  1656  
  1657  	template := &Certificate{
  1658  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1659  		Subject: pkix.Name{
  1660  			OrganizationalUnit: []string{"Leaf"},
  1661  			CommonName:         leaf.cn,
  1662  		},
  1663  		NotBefore:             time.Unix(1000, 0),
  1664  		NotAfter:              time.Unix(2000, 0),
  1665  		KeyUsage:              KeyUsageDigitalSignature,
  1666  		BasicConstraintsValid: true,
  1667  		IsCA:                  false,
  1668  	}
  1669  
  1670  	for _, name := range leaf.sans {
  1671  		switch {
  1672  		case strings.HasPrefix(name, "dns:"):
  1673  			template.DNSNames = append(template.DNSNames, name[4:])
  1674  
  1675  		case strings.HasPrefix(name, "ip:"):
  1676  			ip := net.ParseIP(name[3:])
  1677  			if ip == nil {
  1678  				return nil, fmt.Errorf("cannot parse IP %q", name[3:])
  1679  			}
  1680  			template.IPAddresses = append(template.IPAddresses, ip)
  1681  
  1682  		case strings.HasPrefix(name, "invalidip:"):
  1683  			ipBytes, err := hex.DecodeString(name[10:])
  1684  			if err != nil {
  1685  				return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
  1686  			}
  1687  			template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
  1688  
  1689  		case strings.HasPrefix(name, "email:"):
  1690  			template.EmailAddresses = append(template.EmailAddresses, name[6:])
  1691  
  1692  		case strings.HasPrefix(name, "uri:"):
  1693  			uri, err := url.Parse(name[4:])
  1694  			if err != nil {
  1695  				return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
  1696  			}
  1697  			template.URIs = append(template.URIs, uri)
  1698  
  1699  		case strings.HasPrefix(name, "unknown:"):
  1700  			// This is a special case for testing unknown
  1701  			// name types. A custom SAN extension is
  1702  			// injected into the certificate.
  1703  			if len(leaf.sans) != 1 {
  1704  				panic("when using unknown name types, it must be the sole name")
  1705  			}
  1706  
  1707  			template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
  1708  				Id: []int{2, 5, 29, 17},
  1709  				Value: []byte{
  1710  					0x30, // SEQUENCE
  1711  					3,    // three bytes
  1712  					9,    // undefined GeneralName type 9
  1713  					1,
  1714  					1,
  1715  				},
  1716  			})
  1717  
  1718  		default:
  1719  			return nil, fmt.Errorf("unknown name type %q", name)
  1720  		}
  1721  	}
  1722  
  1723  	var err error
  1724  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
  1725  		return nil, err
  1726  	}
  1727  
  1728  	if parent == nil {
  1729  		parent = template
  1730  	}
  1731  
  1732  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1733  	if err != nil {
  1734  		return nil, err
  1735  	}
  1736  
  1737  	return ParseCertificate(derBytes)
  1738  }
  1739  
  1740  func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
  1741  	appendConstraint := func(contents []byte, tag uint8) []byte {
  1742  		contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
  1743  		contents = append(contents, byte(4+len(constraint)) /* length */)
  1744  		contents = append(contents, 0x30 /* SEQUENCE */)
  1745  		contents = append(contents, byte(2+len(constraint)) /* length */)
  1746  		contents = append(contents, byte(typeNum) /* GeneralName type */)
  1747  		contents = append(contents, byte(len(constraint)))
  1748  		return append(contents, constraint...)
  1749  	}
  1750  
  1751  	var contents []byte
  1752  	if !isExcluded {
  1753  		contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
  1754  	} else {
  1755  		contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
  1756  	}
  1757  
  1758  	var value []byte
  1759  	value = append(value, 0x30 /* SEQUENCE */)
  1760  	value = append(value, byte(len(contents)))
  1761  	value = append(value, contents...)
  1762  
  1763  	return pkix.Extension{
  1764  		Id:    []int{2, 5, 29, 30},
  1765  		Value: value,
  1766  	}
  1767  }
  1768  
  1769  func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
  1770  	parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
  1771  		for _, constraint := range constraints {
  1772  			switch {
  1773  			case strings.HasPrefix(constraint, "dns:"):
  1774  				dnsNames = append(dnsNames, constraint[4:])
  1775  
  1776  			case strings.HasPrefix(constraint, "ip:"):
  1777  				_, ipNet, err := net.ParseCIDR(constraint[3:])
  1778  				if err != nil {
  1779  					return nil, nil, nil, nil, err
  1780  				}
  1781  				ips = append(ips, ipNet)
  1782  
  1783  			case strings.HasPrefix(constraint, "email:"):
  1784  				emailAddrs = append(emailAddrs, constraint[6:])
  1785  
  1786  			case strings.HasPrefix(constraint, "uri:"):
  1787  				uriDomains = append(uriDomains, constraint[4:])
  1788  
  1789  			default:
  1790  				return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
  1791  			}
  1792  		}
  1793  
  1794  		return dnsNames, ips, emailAddrs, uriDomains, err
  1795  	}
  1796  
  1797  	handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
  1798  		switch {
  1799  		case constraint == "unknown:":
  1800  			template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
  1801  
  1802  		default:
  1803  			return false
  1804  		}
  1805  
  1806  		return true
  1807  	}
  1808  
  1809  	if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
  1810  		if handleSpecialConstraint(constraints.ok[0], false) {
  1811  			return nil
  1812  		}
  1813  	}
  1814  
  1815  	if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
  1816  		if handleSpecialConstraint(constraints.bad[0], true) {
  1817  			return nil
  1818  		}
  1819  	}
  1820  
  1821  	var err error
  1822  	template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
  1823  	if err != nil {
  1824  		return err
  1825  	}
  1826  
  1827  	template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
  1828  	if err != nil {
  1829  		return err
  1830  	}
  1831  
  1832  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
  1833  		return err
  1834  	}
  1835  
  1836  	return nil
  1837  }
  1838  
  1839  func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
  1840  	for _, s := range ekuStrs {
  1841  		switch s {
  1842  		case "serverAuth":
  1843  			ekus = append(ekus, ExtKeyUsageServerAuth)
  1844  		case "clientAuth":
  1845  			ekus = append(ekus, ExtKeyUsageClientAuth)
  1846  		case "email":
  1847  			ekus = append(ekus, ExtKeyUsageEmailProtection)
  1848  		case "netscapeSGC":
  1849  			ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
  1850  		case "msSGC":
  1851  			ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
  1852  		case "any":
  1853  			ekus = append(ekus, ExtKeyUsageAny)
  1854  		case "other":
  1855  			unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
  1856  		default:
  1857  			return nil, nil, fmt.Errorf("unknown EKU %q", s)
  1858  		}
  1859  	}
  1860  
  1861  	return
  1862  }
  1863  
  1864  func TestConstraintCases(t *testing.T) {
  1865  	privateKeys := sync.Pool{
  1866  		New: func() any {
  1867  			priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  1868  			if err != nil {
  1869  				panic(err)
  1870  			}
  1871  			return priv
  1872  		},
  1873  	}
  1874  
  1875  	for i, test := range nameConstraintsTests {
  1876  		t.Run(test.name, func(t *testing.T) {
  1877  			rootPool := NewCertPool()
  1878  			rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1879  			rootName := "Root " + strconv.Itoa(i)
  1880  
  1881  			// keys keeps track of all the private keys used in a given
  1882  			// test and puts them back in the privateKeys pool at the end.
  1883  			keys := []*ecdsa.PrivateKey{rootKey}
  1884  
  1885  			// At each level (root, intermediate(s), leaf), parent points to
  1886  			// an example parent certificate and parentKey the key for the
  1887  			// parent level. Since all certificates at a given level have
  1888  			// the same name and public key, any parent certificate is
  1889  			// sufficient to get the correct issuer name and authority
  1890  			// key ID.
  1891  			var parent *Certificate
  1892  			parentKey := rootKey
  1893  
  1894  			for _, root := range test.roots {
  1895  				rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
  1896  				if err != nil {
  1897  					t.Fatalf("failed to create root: %s", err)
  1898  				}
  1899  
  1900  				parent = rootCert
  1901  				rootPool.AddCert(rootCert)
  1902  			}
  1903  
  1904  			intermediatePool := NewCertPool()
  1905  
  1906  			for level, intermediates := range test.intermediates {
  1907  				levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1908  				keys = append(keys, levelKey)
  1909  				levelName := "Intermediate level " + strconv.Itoa(level)
  1910  				var last *Certificate
  1911  
  1912  				for _, intermediate := range intermediates {
  1913  					caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
  1914  					if err != nil {
  1915  						t.Fatalf("failed to create %q: %s", levelName, err)
  1916  					}
  1917  
  1918  					last = caCert
  1919  					intermediatePool.AddCert(caCert)
  1920  				}
  1921  
  1922  				parent = last
  1923  				parentKey = levelKey
  1924  			}
  1925  
  1926  			leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1927  			keys = append(keys, leafKey)
  1928  
  1929  			leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
  1930  			if err != nil {
  1931  				t.Fatalf("cannot create leaf: %s", err)
  1932  			}
  1933  
  1934  			// Skip tests with CommonName set because OpenSSL will try to match it
  1935  			// against name constraints, while we ignore it when it's not hostname-looking.
  1936  			if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
  1937  				output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
  1938  				if err == nil && len(test.expectedError) > 0 {
  1939  					t.Error("unexpectedly succeeded against OpenSSL")
  1940  					if debugOpenSSLFailure {
  1941  						return
  1942  					}
  1943  				}
  1944  
  1945  				if err != nil {
  1946  					if _, ok := err.(*exec.ExitError); !ok {
  1947  						t.Errorf("OpenSSL failed to run: %s", err)
  1948  					} else if len(test.expectedError) == 0 {
  1949  						t.Errorf("OpenSSL unexpectedly failed: %v", output)
  1950  						if debugOpenSSLFailure {
  1951  							return
  1952  						}
  1953  					}
  1954  				}
  1955  			}
  1956  
  1957  			verifyOpts := VerifyOptions{
  1958  				Roots:         rootPool,
  1959  				Intermediates: intermediatePool,
  1960  				CurrentTime:   time.Unix(1500, 0),
  1961  				KeyUsages:     test.requestedEKUs,
  1962  			}
  1963  			_, err = leafCert.Verify(verifyOpts)
  1964  
  1965  			logInfo := false
  1966  			if len(test.expectedError) == 0 {
  1967  				if err != nil {
  1968  					t.Errorf("unexpected failure: %s", err)
  1969  				} else {
  1970  					logInfo = false
  1971  				}
  1972  			} else {
  1973  				if err == nil {
  1974  					t.Error("unexpected success")
  1975  				} else if !strings.Contains(err.Error(), test.expectedError) {
  1976  					t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
  1977  				} else {
  1978  					logInfo = false
  1979  				}
  1980  			}
  1981  
  1982  			if logInfo {
  1983  				certAsPEM := func(cert *Certificate) string {
  1984  					var buf bytes.Buffer
  1985  					pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
  1986  					return buf.String()
  1987  				}
  1988  				t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
  1989  				if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
  1990  					for ii, intermediate := range intermediates {
  1991  						t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
  1992  					}
  1993  				}
  1994  				t.Errorf("leaf:\n%s", certAsPEM(leafCert))
  1995  			}
  1996  
  1997  			for _, key := range keys {
  1998  				privateKeys.Put(key)
  1999  			}
  2000  		})
  2001  	}
  2002  }
  2003  
  2004  func writePEMsToTempFile(certs []*Certificate) *os.File {
  2005  	file, err := os.CreateTemp("", "name_constraints_test")
  2006  	if err != nil {
  2007  		panic("cannot create tempfile")
  2008  	}
  2009  
  2010  	pemBlock := &pem.Block{Type: "CERTIFICATE"}
  2011  	for _, cert := range certs {
  2012  		pemBlock.Bytes = cert.Raw
  2013  		pem.Encode(file, pemBlock)
  2014  	}
  2015  
  2016  	return file
  2017  }
  2018  
  2019  func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
  2020  	args := []string{"verify", "-no_check_time"}
  2021  
  2022  	rootsFile := writePEMsToTempFile(allCerts(t, roots))
  2023  	if debugOpenSSLFailure {
  2024  		println("roots file:", rootsFile.Name())
  2025  	} else {
  2026  		defer os.Remove(rootsFile.Name())
  2027  	}
  2028  	args = append(args, "-CAfile", rootsFile.Name())
  2029  
  2030  	if intermediates.len() > 0 {
  2031  		intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
  2032  		if debugOpenSSLFailure {
  2033  			println("intermediates file:", intermediatesFile.Name())
  2034  		} else {
  2035  			defer os.Remove(intermediatesFile.Name())
  2036  		}
  2037  		args = append(args, "-untrusted", intermediatesFile.Name())
  2038  	}
  2039  
  2040  	leafFile := writePEMsToTempFile([]*Certificate{leaf})
  2041  	if debugOpenSSLFailure {
  2042  		println("leaf file:", leafFile.Name())
  2043  	} else {
  2044  		defer os.Remove(leafFile.Name())
  2045  	}
  2046  	args = append(args, leafFile.Name())
  2047  
  2048  	cmd := testenv.Command(t, "openssl", args...)
  2049  	out, err := cmd.CombinedOutput()
  2050  	return string(out), err
  2051  }
  2052  
  2053  var rfc2821Tests = []struct {
  2054  	in                string
  2055  	localPart, domain string
  2056  }{
  2057  	{"foo@example.com", "foo", "example.com"},
  2058  	{"@example.com", "", ""},
  2059  	{"\"@example.com", "", ""},
  2060  	{"\"\"@example.com", "", "example.com"},
  2061  	{"\"a\"@example.com", "a", "example.com"},
  2062  	{"\"\\a\"@example.com", "a", "example.com"},
  2063  	{"a\"@example.com", "", ""},
  2064  	{"foo..bar@example.com", "", ""},
  2065  	{".foo.bar@example.com", "", ""},
  2066  	{"foo.bar.@example.com", "", ""},
  2067  	{"|{}?'@example.com", "|{}?'", "example.com"},
  2068  
  2069  	// Examples from RFC 3696
  2070  	{"Abc\\@def@example.com", "Abc@def", "example.com"},
  2071  	{"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
  2072  	{"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
  2073  	{"\"Abc@def\"@example.com", "Abc@def", "example.com"},
  2074  	{"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
  2075  	{"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
  2076  	{"$A12345@example.com", "$A12345", "example.com"},
  2077  	{"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
  2078  	{"_somename@example.com", "_somename", "example.com"},
  2079  }
  2080  
  2081  func TestRFC2821Parsing(t *testing.T) {
  2082  	for i, test := range rfc2821Tests {
  2083  		mailbox, ok := parseRFC2821Mailbox(test.in)
  2084  		expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
  2085  
  2086  		if ok && expectedFailure {
  2087  			t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
  2088  			continue
  2089  		}
  2090  
  2091  		if !ok && !expectedFailure {
  2092  			t.Errorf("#%d: unexpected failure for %q", i, test.in)
  2093  			continue
  2094  		}
  2095  
  2096  		if !ok {
  2097  			continue
  2098  		}
  2099  
  2100  		if mailbox.local != test.localPart || mailbox.domain != test.domain {
  2101  			t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
  2102  		}
  2103  	}
  2104  }
  2105  
  2106  func TestBadNamesInConstraints(t *testing.T) {
  2107  	constraintParseError := func(err error) bool {
  2108  		str := err.Error()
  2109  		return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
  2110  	}
  2111  
  2112  	encodingError := func(err error) bool {
  2113  		return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
  2114  	}
  2115  
  2116  	// Bad names in constraints should not parse.
  2117  	badNames := []struct {
  2118  		name    string
  2119  		matcher func(error) bool
  2120  	}{
  2121  		{"dns:foo.com.", constraintParseError},
  2122  		{"email:abc@foo.com.", constraintParseError},
  2123  		{"email:foo.com.", constraintParseError},
  2124  		{"uri:example.com.", constraintParseError},
  2125  		{"uri:1.2.3.4", constraintParseError},
  2126  		{"uri:ffff::1", constraintParseError},
  2127  		{"dns:not–hyphen.com", encodingError},
  2128  		{"email:foo@not–hyphen.com", encodingError},
  2129  		{"uri:not–hyphen.com", encodingError},
  2130  	}
  2131  
  2132  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2133  	if err != nil {
  2134  		panic(err)
  2135  	}
  2136  
  2137  	for _, test := range badNames {
  2138  		_, err := makeConstraintsCACert(constraintsSpec{
  2139  			ok: []string{test.name},
  2140  		}, "TestAbsoluteNamesInConstraints", priv, nil, priv)
  2141  
  2142  		if err == nil {
  2143  			t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
  2144  			continue
  2145  		} else {
  2146  			if !test.matcher(err) {
  2147  				t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
  2148  			}
  2149  		}
  2150  	}
  2151  }
  2152  
  2153  func TestBadNamesInSANs(t *testing.T) {
  2154  	// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
  2155  	// will parse and are tested in name constraint tests at the top of this
  2156  	// file.
  2157  	badNames := []string{
  2158  		"uri:https://example.com./dsf",
  2159  		"invalidip:0102",
  2160  		"invalidip:0102030405",
  2161  	}
  2162  
  2163  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2164  	if err != nil {
  2165  		panic(err)
  2166  	}
  2167  
  2168  	for _, badName := range badNames {
  2169  		_, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
  2170  
  2171  		if err == nil {
  2172  			t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
  2173  			continue
  2174  		}
  2175  
  2176  		if str := err.Error(); !strings.Contains(str, "cannot parse ") {
  2177  			t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
  2178  		}
  2179  	}
  2180  }
  2181  

View as plain text