...

Source file src/crypto/x509/name_constraints_test.go

Documentation: crypto/x509

     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  	"math/big"
    18  	"net"
    19  	"net/url"
    20  	"os"
    21  	"os/exec"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  )
    28  
    29  const (
    30  	// testNameConstraintsAgainstOpenSSL can be set to true to run tests
    31  	// against the system OpenSSL. This is disabled by default because Go
    32  	// cannot depend on having OpenSSL installed at testing time.
    33  	testNameConstraintsAgainstOpenSSL = false
    34  
    35  	// debugOpenSSLFailure can be set to true, when
    36  	// testNameConstraintsAgainstOpenSSL is also true, to cause
    37  	// intermediate files to be preserved for debugging.
    38  	debugOpenSSLFailure = false
    39  )
    40  
    41  type nameConstraintsTest struct {
    42  	roots         []constraintsSpec
    43  	intermediates [][]constraintsSpec
    44  	leaf          leafSpec
    45  	requestedEKUs []ExtKeyUsage
    46  	expectedError string
    47  	noOpenSSL     bool
    48  	ignoreCN      bool
    49  }
    50  
    51  type constraintsSpec struct {
    52  	ok   []string
    53  	bad  []string
    54  	ekus []string
    55  }
    56  
    57  type leafSpec struct {
    58  	sans []string
    59  	ekus []string
    60  	cn   string
    61  }
    62  
    63  var nameConstraintsTests = []nameConstraintsTest{
    64  	// #0: dummy test for the certificate generation process itself.
    65  	{
    66  		roots: make([]constraintsSpec, 1),
    67  		leaf: leafSpec{
    68  			sans: []string{"dns:example.com"},
    69  		},
    70  	},
    71  
    72  	// #1: dummy test for the certificate generation process itself: single
    73  	// level of intermediate.
    74  	{
    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  	// #2: dummy test for the certificate generation process itself: two
    87  	// levels of intermediates.
    88  	{
    89  		roots: make([]constraintsSpec, 1),
    90  		intermediates: [][]constraintsSpec{
    91  			{
    92  				{},
    93  			},
    94  			{
    95  				{},
    96  			},
    97  		},
    98  		leaf: leafSpec{
    99  			sans: []string{"dns:example.com"},
   100  		},
   101  	},
   102  
   103  	// #3: matching DNS constraint in root
   104  	{
   105  		roots: []constraintsSpec{
   106  			{
   107  				ok: []string{"dns:example.com"},
   108  			},
   109  		},
   110  		intermediates: [][]constraintsSpec{
   111  			{
   112  				{},
   113  			},
   114  		},
   115  		leaf: leafSpec{
   116  			sans: []string{"dns:example.com"},
   117  		},
   118  	},
   119  
   120  	// #4: matching DNS constraint in intermediate.
   121  	{
   122  		roots: make([]constraintsSpec, 1),
   123  		intermediates: [][]constraintsSpec{
   124  			{
   125  				{
   126  					ok: []string{"dns:example.com"},
   127  				},
   128  			},
   129  		},
   130  		leaf: leafSpec{
   131  			sans: []string{"dns:example.com"},
   132  		},
   133  	},
   134  
   135  	// #5: .example.com only matches subdomains.
   136  	{
   137  		roots: []constraintsSpec{
   138  			{
   139  				ok: []string{"dns:.example.com"},
   140  			},
   141  		},
   142  		intermediates: [][]constraintsSpec{
   143  			{
   144  				{},
   145  			},
   146  		},
   147  		leaf: leafSpec{
   148  			sans: []string{"dns:example.com"},
   149  		},
   150  		expectedError: "\"example.com\" is not permitted",
   151  	},
   152  
   153  	// #6: .example.com matches subdomains.
   154  	{
   155  		roots: make([]constraintsSpec, 1),
   156  		intermediates: [][]constraintsSpec{
   157  			{
   158  				{
   159  					ok: []string{"dns:.example.com"},
   160  				},
   161  			},
   162  		},
   163  		leaf: leafSpec{
   164  			sans: []string{"dns:foo.example.com"},
   165  		},
   166  	},
   167  
   168  	// #7: .example.com matches multiple levels of subdomains
   169  	{
   170  		roots: []constraintsSpec{
   171  			{
   172  				ok: []string{"dns:.example.com"},
   173  			},
   174  		},
   175  		intermediates: [][]constraintsSpec{
   176  			{
   177  				{},
   178  			},
   179  		},
   180  		leaf: leafSpec{
   181  			sans: []string{"dns:foo.bar.example.com"},
   182  		},
   183  	},
   184  
   185  	// #8: specifying a permitted list of names does not exclude other name
   186  	// types
   187  	{
   188  		roots: []constraintsSpec{
   189  			{
   190  				ok: []string{"dns:.example.com"},
   191  			},
   192  		},
   193  		intermediates: [][]constraintsSpec{
   194  			{
   195  				{},
   196  			},
   197  		},
   198  		leaf: leafSpec{
   199  			sans: []string{"ip:10.1.1.1"},
   200  		},
   201  	},
   202  
   203  	// #9: specifying a permitted list of names does not exclude other name
   204  	// types
   205  	{
   206  		roots: []constraintsSpec{
   207  			{
   208  				ok: []string{"ip:10.0.0.0/8"},
   209  			},
   210  		},
   211  		intermediates: [][]constraintsSpec{
   212  			{
   213  				{},
   214  			},
   215  		},
   216  		leaf: leafSpec{
   217  			sans: []string{"dns:example.com"},
   218  		},
   219  	},
   220  
   221  	// #10: intermediates can try to permit other names, which isn't
   222  	// forbidden if the leaf doesn't mention them. I.e. name constraints
   223  	// apply to names, not constraints themselves.
   224  	{
   225  		roots: []constraintsSpec{
   226  			{
   227  				ok: []string{"dns:example.com"},
   228  			},
   229  		},
   230  		intermediates: [][]constraintsSpec{
   231  			{
   232  				{
   233  					ok: []string{"dns:example.com", "dns:foo.com"},
   234  				},
   235  			},
   236  		},
   237  		leaf: leafSpec{
   238  			sans: []string{"dns:example.com"},
   239  		},
   240  	},
   241  
   242  	// #11: intermediates cannot add permitted names that the root doesn't
   243  	// grant them.
   244  	{
   245  		roots: []constraintsSpec{
   246  			{
   247  				ok: []string{"dns:example.com"},
   248  			},
   249  		},
   250  		intermediates: [][]constraintsSpec{
   251  			{
   252  				{
   253  					ok: []string{"dns:example.com", "dns:foo.com"},
   254  				},
   255  			},
   256  		},
   257  		leaf: leafSpec{
   258  			sans: []string{"dns:foo.com"},
   259  		},
   260  		expectedError: "\"foo.com\" is not permitted",
   261  	},
   262  
   263  	// #12: intermediates can further limit their scope if they wish.
   264  	{
   265  		roots: []constraintsSpec{
   266  			{
   267  				ok: []string{"dns:.example.com"},
   268  			},
   269  		},
   270  		intermediates: [][]constraintsSpec{
   271  			{
   272  				{
   273  					ok: []string{"dns:.bar.example.com"},
   274  				},
   275  			},
   276  		},
   277  		leaf: leafSpec{
   278  			sans: []string{"dns:foo.bar.example.com"},
   279  		},
   280  	},
   281  
   282  	// #13: intermediates can further limit their scope and that limitation
   283  	// is effective
   284  	{
   285  		roots: []constraintsSpec{
   286  			{
   287  				ok: []string{"dns:.example.com"},
   288  			},
   289  		},
   290  		intermediates: [][]constraintsSpec{
   291  			{
   292  				{
   293  					ok: []string{"dns:.bar.example.com"},
   294  				},
   295  			},
   296  		},
   297  		leaf: leafSpec{
   298  			sans: []string{"dns:foo.notbar.example.com"},
   299  		},
   300  		expectedError: "\"foo.notbar.example.com\" is not permitted",
   301  	},
   302  
   303  	// #14: roots can exclude subtrees and that doesn't affect other names.
   304  	{
   305  		roots: []constraintsSpec{
   306  			{
   307  				bad: []string{"dns:.example.com"},
   308  			},
   309  		},
   310  		intermediates: [][]constraintsSpec{
   311  			{
   312  				{},
   313  			},
   314  		},
   315  		leaf: leafSpec{
   316  			sans: []string{"dns:foo.com"},
   317  		},
   318  	},
   319  
   320  	// #15: roots exclusions are effective.
   321  	{
   322  		roots: []constraintsSpec{
   323  			{
   324  				bad: []string{"dns:.example.com"},
   325  			},
   326  		},
   327  		intermediates: [][]constraintsSpec{
   328  			{
   329  				{},
   330  			},
   331  		},
   332  		leaf: leafSpec{
   333  			sans: []string{"dns:foo.example.com"},
   334  		},
   335  		expectedError: "\"foo.example.com\" is excluded",
   336  	},
   337  
   338  	// #16: intermediates can also exclude names and that doesn't affect
   339  	// other names.
   340  	{
   341  		roots: make([]constraintsSpec, 1),
   342  		intermediates: [][]constraintsSpec{
   343  			{
   344  				{
   345  					bad: []string{"dns:.example.com"},
   346  				},
   347  			},
   348  		},
   349  		leaf: leafSpec{
   350  			sans: []string{"dns:foo.com"},
   351  		},
   352  	},
   353  
   354  	// #17: intermediate exclusions are effective.
   355  	{
   356  		roots: make([]constraintsSpec, 1),
   357  		intermediates: [][]constraintsSpec{
   358  			{
   359  				{
   360  					bad: []string{"dns:.example.com"},
   361  				},
   362  			},
   363  		},
   364  		leaf: leafSpec{
   365  			sans: []string{"dns:foo.example.com"},
   366  		},
   367  		expectedError: "\"foo.example.com\" is excluded",
   368  	},
   369  
   370  	// #18: having an exclusion doesn't prohibit other types of names.
   371  	{
   372  		roots: []constraintsSpec{
   373  			{
   374  				bad: []string{"dns:.example.com"},
   375  			},
   376  		},
   377  		intermediates: [][]constraintsSpec{
   378  			{
   379  				{},
   380  			},
   381  		},
   382  		leaf: leafSpec{
   383  			sans: []string{"dns:foo.com", "ip:10.1.1.1"},
   384  		},
   385  	},
   386  
   387  	// #19: IP-based exclusions are permitted and don't affect unrelated IP
   388  	// addresses.
   389  	{
   390  		roots: []constraintsSpec{
   391  			{
   392  				bad: []string{"ip:10.0.0.0/8"},
   393  			},
   394  		},
   395  		intermediates: [][]constraintsSpec{
   396  			{
   397  				{},
   398  			},
   399  		},
   400  		leaf: leafSpec{
   401  			sans: []string{"ip:192.168.1.1"},
   402  		},
   403  	},
   404  
   405  	// #20: IP-based exclusions are effective
   406  	{
   407  		roots: []constraintsSpec{
   408  			{
   409  				bad: []string{"ip:10.0.0.0/8"},
   410  			},
   411  		},
   412  		intermediates: [][]constraintsSpec{
   413  			{
   414  				{},
   415  			},
   416  		},
   417  		leaf: leafSpec{
   418  			sans: []string{"ip:10.0.0.1"},
   419  		},
   420  		expectedError: "\"10.0.0.1\" is excluded",
   421  	},
   422  
   423  	// #21: intermediates can further constrain IP ranges.
   424  	{
   425  		roots: []constraintsSpec{
   426  			{
   427  				bad: []string{"ip:0.0.0.0/1"},
   428  			},
   429  		},
   430  		intermediates: [][]constraintsSpec{
   431  			{
   432  				{
   433  					bad: []string{"ip:11.0.0.0/8"},
   434  				},
   435  			},
   436  		},
   437  		leaf: leafSpec{
   438  			sans: []string{"ip:11.0.0.1"},
   439  		},
   440  		expectedError: "\"11.0.0.1\" is excluded",
   441  	},
   442  
   443  	// #22: when multiple intermediates are present, chain building can
   444  	// avoid intermediates with incompatible constraints.
   445  	{
   446  		roots: make([]constraintsSpec, 1),
   447  		intermediates: [][]constraintsSpec{
   448  			{
   449  				{
   450  					ok: []string{"dns:.foo.com"},
   451  				},
   452  				{
   453  					ok: []string{"dns:.example.com"},
   454  				},
   455  			},
   456  		},
   457  		leaf: leafSpec{
   458  			sans: []string{"dns:foo.example.com"},
   459  		},
   460  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   461  	},
   462  
   463  	// #23: (same as the previous test, but in the other order in ensure
   464  	// that we don't pass it by luck.)
   465  	{
   466  		roots: make([]constraintsSpec, 1),
   467  		intermediates: [][]constraintsSpec{
   468  			{
   469  				{
   470  					ok: []string{"dns:.example.com"},
   471  				},
   472  				{
   473  					ok: []string{"dns:.foo.com"},
   474  				},
   475  			},
   476  		},
   477  		leaf: leafSpec{
   478  			sans: []string{"dns:foo.example.com"},
   479  		},
   480  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   481  	},
   482  
   483  	// #24: when multiple roots are valid, chain building can avoid roots
   484  	// with incompatible constraints.
   485  	{
   486  		roots: []constraintsSpec{
   487  			{},
   488  			{
   489  				ok: []string{"dns:foo.com"},
   490  			},
   491  		},
   492  		intermediates: [][]constraintsSpec{
   493  			{
   494  				{},
   495  			},
   496  		},
   497  		leaf: leafSpec{
   498  			sans: []string{"dns:example.com"},
   499  		},
   500  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   501  	},
   502  
   503  	// #25: (same as the previous test, but in the other order in ensure
   504  	// that we don't pass it by luck.)
   505  	{
   506  		roots: []constraintsSpec{
   507  			{
   508  				ok: []string{"dns:foo.com"},
   509  			},
   510  			{},
   511  		},
   512  		intermediates: [][]constraintsSpec{
   513  			{
   514  				{},
   515  			},
   516  		},
   517  		leaf: leafSpec{
   518  			sans: []string{"dns:example.com"},
   519  		},
   520  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   521  	},
   522  
   523  	// #26: chain building can find a valid path even with multiple levels
   524  	// of alternative intermediates and alternative roots.
   525  	{
   526  		roots: []constraintsSpec{
   527  			{
   528  				ok: []string{"dns:foo.com"},
   529  			},
   530  			{
   531  				ok: []string{"dns:example.com"},
   532  			},
   533  			{},
   534  		},
   535  		intermediates: [][]constraintsSpec{
   536  			{
   537  				{},
   538  				{
   539  					ok: []string{"dns:foo.com"},
   540  				},
   541  			},
   542  			{
   543  				{},
   544  				{
   545  					ok: []string{"dns:foo.com"},
   546  				},
   547  			},
   548  		},
   549  		leaf: leafSpec{
   550  			sans: []string{"dns:bar.com"},
   551  		},
   552  		noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
   553  	},
   554  
   555  	// #27: chain building doesn't get stuck when there is no valid path.
   556  	{
   557  		roots: []constraintsSpec{
   558  			{
   559  				ok: []string{"dns:foo.com"},
   560  			},
   561  			{
   562  				ok: []string{"dns:example.com"},
   563  			},
   564  		},
   565  		intermediates: [][]constraintsSpec{
   566  			{
   567  				{},
   568  				{
   569  					ok: []string{"dns:foo.com"},
   570  				},
   571  			},
   572  			{
   573  				{
   574  					ok: []string{"dns:bar.com"},
   575  				},
   576  				{
   577  					ok: []string{"dns:foo.com"},
   578  				},
   579  			},
   580  		},
   581  		leaf: leafSpec{
   582  			sans: []string{"dns:bar.com"},
   583  		},
   584  		expectedError: "\"bar.com\" is not permitted",
   585  	},
   586  
   587  	// #28: unknown name types don't cause a problem without constraints.
   588  	{
   589  		roots: make([]constraintsSpec, 1),
   590  		intermediates: [][]constraintsSpec{
   591  			{
   592  				{},
   593  			},
   594  		},
   595  		leaf: leafSpec{
   596  			sans: []string{"unknown:"},
   597  		},
   598  	},
   599  
   600  	// #29: unknown name types are allowed even in constrained chains.
   601  	{
   602  		roots: []constraintsSpec{
   603  			{
   604  				ok: []string{"dns:foo.com", "dns:.foo.com"},
   605  			},
   606  		},
   607  		intermediates: [][]constraintsSpec{
   608  			{
   609  				{},
   610  			},
   611  		},
   612  		leaf: leafSpec{
   613  			sans: []string{"unknown:"},
   614  		},
   615  	},
   616  
   617  	// #30: without SANs, a certificate with a CN is still accepted in a
   618  	// constrained chain, since we ignore the CN in VerifyHostname.
   619  	{
   620  		roots: []constraintsSpec{
   621  			{
   622  				ok: []string{"dns:foo.com", "dns:.foo.com"},
   623  			},
   624  		},
   625  		intermediates: [][]constraintsSpec{
   626  			{
   627  				{},
   628  			},
   629  		},
   630  		leaf: leafSpec{
   631  			sans: []string{},
   632  			cn:   "foo.com",
   633  		},
   634  	},
   635  
   636  	// #31: IPv6 addresses work in constraints: roots can permit them as
   637  	// expected.
   638  	{
   639  		roots: []constraintsSpec{
   640  			{
   641  				ok: []string{"ip:2000:abcd::/32"},
   642  			},
   643  		},
   644  		intermediates: [][]constraintsSpec{
   645  			{
   646  				{},
   647  			},
   648  		},
   649  		leaf: leafSpec{
   650  			sans: []string{"ip:2000:abcd:1234::"},
   651  		},
   652  	},
   653  
   654  	// #32: IPv6 addresses work in constraints: root restrictions are
   655  	// effective.
   656  	{
   657  		roots: []constraintsSpec{
   658  			{
   659  				ok: []string{"ip:2000:abcd::/32"},
   660  			},
   661  		},
   662  		intermediates: [][]constraintsSpec{
   663  			{
   664  				{},
   665  			},
   666  		},
   667  		leaf: leafSpec{
   668  			sans: []string{"ip:2000:1234:abcd::"},
   669  		},
   670  		expectedError: "\"2000:1234:abcd::\" is not permitted",
   671  	},
   672  
   673  	// #33: An IPv6 permitted subtree doesn't affect DNS names.
   674  	{
   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:2000:abcd::", "dns:foo.com"},
   687  		},
   688  	},
   689  
   690  	// #34: IPv6 exclusions don't affect unrelated addresses.
   691  	{
   692  		roots: []constraintsSpec{
   693  			{
   694  				bad: []string{"ip:2000:abcd::/32"},
   695  			},
   696  		},
   697  		intermediates: [][]constraintsSpec{
   698  			{
   699  				{},
   700  			},
   701  		},
   702  		leaf: leafSpec{
   703  			sans: []string{"ip:2000:1234::"},
   704  		},
   705  	},
   706  
   707  	// #35: IPv6 exclusions are effective.
   708  	{
   709  		roots: []constraintsSpec{
   710  			{
   711  				bad: []string{"ip:2000:abcd::/32"},
   712  			},
   713  		},
   714  		intermediates: [][]constraintsSpec{
   715  			{
   716  				{},
   717  			},
   718  		},
   719  		leaf: leafSpec{
   720  			sans: []string{"ip:2000:abcd::"},
   721  		},
   722  		expectedError: "\"2000:abcd::\" is excluded",
   723  	},
   724  
   725  	// #36: IPv6 constraints do not permit IPv4 addresses.
   726  	{
   727  		roots: []constraintsSpec{
   728  			{
   729  				ok: []string{"ip:2000:abcd::/32"},
   730  			},
   731  		},
   732  		intermediates: [][]constraintsSpec{
   733  			{
   734  				{},
   735  			},
   736  		},
   737  		leaf: leafSpec{
   738  			sans: []string{"ip:10.0.0.1"},
   739  		},
   740  		expectedError: "\"10.0.0.1\" is not permitted",
   741  	},
   742  
   743  	// #37: IPv4 constraints do not permit IPv6 addresses.
   744  	{
   745  		roots: []constraintsSpec{
   746  			{
   747  				ok: []string{"ip:10.0.0.0/8"},
   748  			},
   749  		},
   750  		intermediates: [][]constraintsSpec{
   751  			{
   752  				{},
   753  			},
   754  		},
   755  		leaf: leafSpec{
   756  			sans: []string{"ip:2000:abcd::"},
   757  		},
   758  		expectedError: "\"2000:abcd::\" is not permitted",
   759  	},
   760  
   761  	// #38: an exclusion of an unknown type doesn't affect other names.
   762  	{
   763  		roots: []constraintsSpec{
   764  			{
   765  				bad: []string{"unknown:"},
   766  			},
   767  		},
   768  		intermediates: [][]constraintsSpec{
   769  			{
   770  				{},
   771  			},
   772  		},
   773  		leaf: leafSpec{
   774  			sans: []string{"dns:example.com"},
   775  		},
   776  	},
   777  
   778  	// #39: a permitted subtree of an unknown type doesn't affect other
   779  	// name types.
   780  	{
   781  		roots: []constraintsSpec{
   782  			{
   783  				ok: []string{"unknown:"},
   784  			},
   785  		},
   786  		intermediates: [][]constraintsSpec{
   787  			{
   788  				{},
   789  			},
   790  		},
   791  		leaf: leafSpec{
   792  			sans: []string{"dns:example.com"},
   793  		},
   794  	},
   795  
   796  	// #40: exact email constraints work
   797  	{
   798  		roots: []constraintsSpec{
   799  			{
   800  				ok: []string{"email:foo@example.com"},
   801  			},
   802  		},
   803  		intermediates: [][]constraintsSpec{
   804  			{
   805  				{},
   806  			},
   807  		},
   808  		leaf: leafSpec{
   809  			sans: []string{"email:foo@example.com"},
   810  		},
   811  	},
   812  
   813  	// #41: exact email constraints are effective
   814  	{
   815  		roots: []constraintsSpec{
   816  			{
   817  				ok: []string{"email:foo@example.com"},
   818  			},
   819  		},
   820  		intermediates: [][]constraintsSpec{
   821  			{
   822  				{},
   823  			},
   824  		},
   825  		leaf: leafSpec{
   826  			sans: []string{"email:bar@example.com"},
   827  		},
   828  		expectedError: "\"bar@example.com\" is not permitted",
   829  	},
   830  
   831  	// #42: email canonicalisation works.
   832  	{
   833  		roots: []constraintsSpec{
   834  			{
   835  				ok: []string{"email:foo@example.com"},
   836  			},
   837  		},
   838  		intermediates: [][]constraintsSpec{
   839  			{
   840  				{},
   841  			},
   842  		},
   843  		leaf: leafSpec{
   844  			sans: []string{"email:\"\\f\\o\\o\"@example.com"},
   845  		},
   846  		noOpenSSL: true, // OpenSSL doesn't canonicalise email addresses before matching
   847  	},
   848  
   849  	// #43: limiting email addresses to a host works.
   850  	{
   851  		roots: []constraintsSpec{
   852  			{
   853  				ok: []string{"email:example.com"},
   854  			},
   855  		},
   856  		intermediates: [][]constraintsSpec{
   857  			{
   858  				{},
   859  			},
   860  		},
   861  		leaf: leafSpec{
   862  			sans: []string{"email:foo@example.com"},
   863  		},
   864  	},
   865  
   866  	// #44: a leading dot matches hosts one level deep
   867  	{
   868  		roots: []constraintsSpec{
   869  			{
   870  				ok: []string{"email:.example.com"},
   871  			},
   872  		},
   873  		intermediates: [][]constraintsSpec{
   874  			{
   875  				{},
   876  			},
   877  		},
   878  		leaf: leafSpec{
   879  			sans: []string{"email:foo@sub.example.com"},
   880  		},
   881  	},
   882  
   883  	// #45: a leading dot does not match the host itself
   884  	{
   885  		roots: []constraintsSpec{
   886  			{
   887  				ok: []string{"email:.example.com"},
   888  			},
   889  		},
   890  		intermediates: [][]constraintsSpec{
   891  			{
   892  				{},
   893  			},
   894  		},
   895  		leaf: leafSpec{
   896  			sans: []string{"email:foo@example.com"},
   897  		},
   898  		expectedError: "\"foo@example.com\" is not permitted",
   899  	},
   900  
   901  	// #46: a leading dot also matches two (or more) levels deep.
   902  	{
   903  		roots: []constraintsSpec{
   904  			{
   905  				ok: []string{"email:.example.com"},
   906  			},
   907  		},
   908  		intermediates: [][]constraintsSpec{
   909  			{
   910  				{},
   911  			},
   912  		},
   913  		leaf: leafSpec{
   914  			sans: []string{"email:foo@sub.sub.example.com"},
   915  		},
   916  	},
   917  
   918  	// #47: the local part of an email is case-sensitive
   919  	{
   920  		roots: []constraintsSpec{
   921  			{
   922  				ok: []string{"email:foo@example.com"},
   923  			},
   924  		},
   925  		intermediates: [][]constraintsSpec{
   926  			{
   927  				{},
   928  			},
   929  		},
   930  		leaf: leafSpec{
   931  			sans: []string{"email:Foo@example.com"},
   932  		},
   933  		expectedError: "\"Foo@example.com\" is not permitted",
   934  	},
   935  
   936  	// #48: the domain part of an email is not case-sensitive
   937  	{
   938  		roots: []constraintsSpec{
   939  			{
   940  				ok: []string{"email:foo@EXAMPLE.com"},
   941  			},
   942  		},
   943  		intermediates: [][]constraintsSpec{
   944  			{
   945  				{},
   946  			},
   947  		},
   948  		leaf: leafSpec{
   949  			sans: []string{"email:foo@example.com"},
   950  		},
   951  	},
   952  
   953  	// #49: the domain part of a DNS constraint is also not case-sensitive.
   954  	{
   955  		roots: []constraintsSpec{
   956  			{
   957  				ok: []string{"dns:EXAMPLE.com"},
   958  			},
   959  		},
   960  		intermediates: [][]constraintsSpec{
   961  			{
   962  				{},
   963  			},
   964  		},
   965  		leaf: leafSpec{
   966  			sans: []string{"dns:example.com"},
   967  		},
   968  	},
   969  
   970  	// #50: URI constraints only cover the host part of the URI
   971  	{
   972  		roots: []constraintsSpec{
   973  			{
   974  				ok: []string{"uri:example.com"},
   975  			},
   976  		},
   977  		intermediates: [][]constraintsSpec{
   978  			{
   979  				{},
   980  			},
   981  		},
   982  		leaf: leafSpec{
   983  			sans: []string{
   984  				"uri:http://example.com/bar",
   985  				"uri:http://example.com:8080/",
   986  				"uri:https://example.com/wibble#bar",
   987  			},
   988  		},
   989  	},
   990  
   991  	// #51: URIs with IPs are rejected
   992  	{
   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://1.2.3.4/"},
  1005  		},
  1006  		expectedError: "URI with IP",
  1007  	},
  1008  
  1009  	// #52: URIs with IPs and ports are rejected
  1010  	{
  1011  		roots: []constraintsSpec{
  1012  			{
  1013  				ok: []string{"uri:example.com"},
  1014  			},
  1015  		},
  1016  		intermediates: [][]constraintsSpec{
  1017  			{
  1018  				{},
  1019  			},
  1020  		},
  1021  		leaf: leafSpec{
  1022  			sans: []string{"uri:http://1.2.3.4:43/"},
  1023  		},
  1024  		expectedError: "URI with IP",
  1025  	},
  1026  
  1027  	// #53: URIs with IPv6 addresses are also rejected
  1028  	{
  1029  		roots: []constraintsSpec{
  1030  			{
  1031  				ok: []string{"uri:example.com"},
  1032  			},
  1033  		},
  1034  		intermediates: [][]constraintsSpec{
  1035  			{
  1036  				{},
  1037  			},
  1038  		},
  1039  		leaf: leafSpec{
  1040  			sans: []string{"uri:http://[2006:abcd::1]/"},
  1041  		},
  1042  		expectedError: "URI with IP",
  1043  	},
  1044  
  1045  	// #54: URIs with IPv6 addresses with ports are also rejected
  1046  	{
  1047  		roots: []constraintsSpec{
  1048  			{
  1049  				ok: []string{"uri:example.com"},
  1050  			},
  1051  		},
  1052  		intermediates: [][]constraintsSpec{
  1053  			{
  1054  				{},
  1055  			},
  1056  		},
  1057  		leaf: leafSpec{
  1058  			sans: []string{"uri:http://[2006:abcd::1]:16/"},
  1059  		},
  1060  		expectedError: "URI with IP",
  1061  	},
  1062  
  1063  	// #55: URI constraints are effective
  1064  	{
  1065  		roots: []constraintsSpec{
  1066  			{
  1067  				ok: []string{"uri:example.com"},
  1068  			},
  1069  		},
  1070  		intermediates: [][]constraintsSpec{
  1071  			{
  1072  				{},
  1073  			},
  1074  		},
  1075  		leaf: leafSpec{
  1076  			sans: []string{"uri:http://bar.com/"},
  1077  		},
  1078  		expectedError: "\"http://bar.com/\" is not permitted",
  1079  	},
  1080  
  1081  	// #56: URI constraints are effective
  1082  	{
  1083  		roots: []constraintsSpec{
  1084  			{
  1085  				bad: []string{"uri:foo.com"},
  1086  			},
  1087  		},
  1088  		intermediates: [][]constraintsSpec{
  1089  			{
  1090  				{},
  1091  			},
  1092  		},
  1093  		leaf: leafSpec{
  1094  			sans: []string{"uri:http://foo.com/"},
  1095  		},
  1096  		expectedError: "\"http://foo.com/\" is excluded",
  1097  	},
  1098  
  1099  	// #57: URI constraints can allow subdomains
  1100  	{
  1101  		roots: []constraintsSpec{
  1102  			{
  1103  				ok: []string{"uri:.foo.com"},
  1104  			},
  1105  		},
  1106  		intermediates: [][]constraintsSpec{
  1107  			{
  1108  				{},
  1109  			},
  1110  		},
  1111  		leaf: leafSpec{
  1112  			sans: []string{"uri:http://www.foo.com/"},
  1113  		},
  1114  	},
  1115  
  1116  	// #58: excluding an IPv4-mapped-IPv6 address doesn't affect the IPv4
  1117  	// version of that address.
  1118  	{
  1119  		roots: []constraintsSpec{
  1120  			{
  1121  				bad: []string{"ip:::ffff:1.2.3.4/128"},
  1122  			},
  1123  		},
  1124  		intermediates: [][]constraintsSpec{
  1125  			{
  1126  				{},
  1127  			},
  1128  		},
  1129  		leaf: leafSpec{
  1130  			sans: []string{"ip:1.2.3.4"},
  1131  		},
  1132  	},
  1133  
  1134  	// #59: a URI constraint isn't matched by a URN.
  1135  	{
  1136  		roots: []constraintsSpec{
  1137  			{
  1138  				ok: []string{"uri:example.com"},
  1139  			},
  1140  		},
  1141  		intermediates: [][]constraintsSpec{
  1142  			{
  1143  				{},
  1144  			},
  1145  		},
  1146  		leaf: leafSpec{
  1147  			sans: []string{"uri:urn:example"},
  1148  		},
  1149  		expectedError: "URI with empty host",
  1150  	},
  1151  
  1152  	// #60: excluding all IPv6 addresses doesn't exclude all IPv4 addresses
  1153  	// too, even though IPv4 is mapped into the IPv6 range.
  1154  	{
  1155  		roots: []constraintsSpec{
  1156  			{
  1157  				ok:  []string{"ip:1.2.3.0/24"},
  1158  				bad: []string{"ip:::0/0"},
  1159  			},
  1160  		},
  1161  		intermediates: [][]constraintsSpec{
  1162  			{
  1163  				{},
  1164  			},
  1165  		},
  1166  		leaf: leafSpec{
  1167  			sans: []string{"ip:1.2.3.4"},
  1168  		},
  1169  	},
  1170  
  1171  	// #61: omitting extended key usage in a CA certificate implies that
  1172  	// any usage is ok.
  1173  	{
  1174  		roots: make([]constraintsSpec, 1),
  1175  		intermediates: [][]constraintsSpec{
  1176  			{
  1177  				{},
  1178  			},
  1179  		},
  1180  		leaf: leafSpec{
  1181  			sans: []string{"dns:example.com"},
  1182  			ekus: []string{"serverAuth", "other"},
  1183  		},
  1184  	},
  1185  
  1186  	// #62: The “any” EKU also means that any usage is ok.
  1187  	{
  1188  		roots: make([]constraintsSpec, 1),
  1189  		intermediates: [][]constraintsSpec{
  1190  			{
  1191  				{
  1192  					ekus: []string{"any"},
  1193  				},
  1194  			},
  1195  		},
  1196  		leaf: leafSpec{
  1197  			sans: []string{"dns:example.com"},
  1198  			ekus: []string{"serverAuth", "other"},
  1199  		},
  1200  	},
  1201  
  1202  	// #63: An intermediate with enumerated EKUs causes a failure if we
  1203  	// test for an EKU not in that set. (ServerAuth is required by
  1204  	// default.)
  1205  	{
  1206  		roots: make([]constraintsSpec, 1),
  1207  		intermediates: [][]constraintsSpec{
  1208  			{
  1209  				{
  1210  					ekus: []string{"email"},
  1211  				},
  1212  			},
  1213  		},
  1214  		leaf: leafSpec{
  1215  			sans: []string{"dns:example.com"},
  1216  			ekus: []string{"serverAuth"},
  1217  		},
  1218  		expectedError: "incompatible key usage",
  1219  	},
  1220  
  1221  	// #64: an unknown EKU in the leaf doesn't break anything, even if it's not
  1222  	// correctly nested.
  1223  	{
  1224  		roots: make([]constraintsSpec, 1),
  1225  		intermediates: [][]constraintsSpec{
  1226  			{
  1227  				{
  1228  					ekus: []string{"email"},
  1229  				},
  1230  			},
  1231  		},
  1232  		leaf: leafSpec{
  1233  			sans: []string{"dns:example.com"},
  1234  			ekus: []string{"other"},
  1235  		},
  1236  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
  1237  	},
  1238  
  1239  	// #65: trying to add extra permitted key usages in an intermediate
  1240  	// (after a limitation in the root) is acceptable so long as the leaf
  1241  	// certificate doesn't use them.
  1242  	{
  1243  		roots: []constraintsSpec{
  1244  			{
  1245  				ekus: []string{"serverAuth"},
  1246  			},
  1247  		},
  1248  		intermediates: [][]constraintsSpec{
  1249  			{
  1250  				{
  1251  					ekus: []string{"serverAuth", "email"},
  1252  				},
  1253  			},
  1254  		},
  1255  		leaf: leafSpec{
  1256  			sans: []string{"dns:example.com"},
  1257  			ekus: []string{"serverAuth"},
  1258  		},
  1259  	},
  1260  
  1261  	// #66: EKUs in roots are not ignored.
  1262  	{
  1263  		roots: []constraintsSpec{
  1264  			{
  1265  				ekus: []string{"email"},
  1266  			},
  1267  		},
  1268  		intermediates: [][]constraintsSpec{
  1269  			{
  1270  				{
  1271  					ekus: []string{"serverAuth"},
  1272  				},
  1273  			},
  1274  		},
  1275  		leaf: leafSpec{
  1276  			sans: []string{"dns:example.com"},
  1277  			ekus: []string{"serverAuth"},
  1278  		},
  1279  		expectedError: "incompatible key usage",
  1280  	},
  1281  
  1282  	// #67: SGC key usages used to permit serverAuth and clientAuth,
  1283  	// but don't anymore.
  1284  	{
  1285  		roots: []constraintsSpec{
  1286  			{},
  1287  		},
  1288  		intermediates: [][]constraintsSpec{
  1289  			{
  1290  				{
  1291  					ekus: []string{"netscapeSGC"},
  1292  				},
  1293  			},
  1294  		},
  1295  		leaf: leafSpec{
  1296  			sans: []string{"dns:example.com"},
  1297  			ekus: []string{"serverAuth", "clientAuth"},
  1298  		},
  1299  		expectedError: "incompatible key usage",
  1300  	},
  1301  
  1302  	// #68: SGC key usages used to permit serverAuth and clientAuth,
  1303  	// but don't anymore.
  1304  	{
  1305  		roots: make([]constraintsSpec, 1),
  1306  		intermediates: [][]constraintsSpec{
  1307  			{
  1308  				{
  1309  					ekus: []string{"msSGC"},
  1310  				},
  1311  			},
  1312  		},
  1313  		leaf: leafSpec{
  1314  			sans: []string{"dns:example.com"},
  1315  			ekus: []string{"serverAuth", "clientAuth"},
  1316  		},
  1317  		expectedError: "incompatible key usage",
  1318  	},
  1319  
  1320  	// #69: an empty DNS constraint should allow anything.
  1321  	{
  1322  		roots: []constraintsSpec{
  1323  			{
  1324  				ok: []string{"dns:"},
  1325  			},
  1326  		},
  1327  		intermediates: [][]constraintsSpec{
  1328  			{
  1329  				{},
  1330  			},
  1331  		},
  1332  		leaf: leafSpec{
  1333  			sans: []string{"dns:example.com"},
  1334  		},
  1335  	},
  1336  
  1337  	// #70: an empty DNS constraint should also reject everything.
  1338  	{
  1339  		roots: []constraintsSpec{
  1340  			{
  1341  				bad: []string{"dns:"},
  1342  			},
  1343  		},
  1344  		intermediates: [][]constraintsSpec{
  1345  			{
  1346  				{},
  1347  			},
  1348  		},
  1349  		leaf: leafSpec{
  1350  			sans: []string{"dns:example.com"},
  1351  		},
  1352  		expectedError: "\"example.com\" is excluded",
  1353  	},
  1354  
  1355  	// #71: an empty email constraint should allow anything
  1356  	{
  1357  		roots: []constraintsSpec{
  1358  			{
  1359  				ok: []string{"email:"},
  1360  			},
  1361  		},
  1362  		intermediates: [][]constraintsSpec{
  1363  			{
  1364  				{},
  1365  			},
  1366  		},
  1367  		leaf: leafSpec{
  1368  			sans: []string{"email:foo@example.com"},
  1369  		},
  1370  	},
  1371  
  1372  	// #72: an empty email constraint should also reject everything.
  1373  	{
  1374  		roots: []constraintsSpec{
  1375  			{
  1376  				bad: []string{"email:"},
  1377  			},
  1378  		},
  1379  		intermediates: [][]constraintsSpec{
  1380  			{
  1381  				{},
  1382  			},
  1383  		},
  1384  		leaf: leafSpec{
  1385  			sans: []string{"email:foo@example.com"},
  1386  		},
  1387  		expectedError: "\"foo@example.com\" is excluded",
  1388  	},
  1389  
  1390  	// #73: an empty URI constraint should allow anything
  1391  	{
  1392  		roots: []constraintsSpec{
  1393  			{
  1394  				ok: []string{"uri:"},
  1395  			},
  1396  		},
  1397  		intermediates: [][]constraintsSpec{
  1398  			{
  1399  				{},
  1400  			},
  1401  		},
  1402  		leaf: leafSpec{
  1403  			sans: []string{"uri:https://example.com/test"},
  1404  		},
  1405  	},
  1406  
  1407  	// #74: an empty URI constraint should also reject everything.
  1408  	{
  1409  		roots: []constraintsSpec{
  1410  			{
  1411  				bad: []string{"uri:"},
  1412  			},
  1413  		},
  1414  		intermediates: [][]constraintsSpec{
  1415  			{
  1416  				{},
  1417  			},
  1418  		},
  1419  		leaf: leafSpec{
  1420  			sans: []string{"uri:https://example.com/test"},
  1421  		},
  1422  		expectedError: "\"https://example.com/test\" is excluded",
  1423  	},
  1424  
  1425  	// #75: serverAuth in a leaf shouldn't permit clientAuth when requested in
  1426  	// VerifyOptions.
  1427  	{
  1428  		roots: make([]constraintsSpec, 1),
  1429  		intermediates: [][]constraintsSpec{
  1430  			{
  1431  				{},
  1432  			},
  1433  		},
  1434  		leaf: leafSpec{
  1435  			sans: []string{"dns:example.com"},
  1436  			ekus: []string{"serverAuth"},
  1437  		},
  1438  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
  1439  		expectedError: "incompatible key usage",
  1440  	},
  1441  
  1442  	// #76: MSSGC in a leaf used to match a request for serverAuth, but doesn't
  1443  	// anymore.
  1444  	{
  1445  		roots: make([]constraintsSpec, 1),
  1446  		intermediates: [][]constraintsSpec{
  1447  			{
  1448  				{},
  1449  			},
  1450  		},
  1451  		leaf: leafSpec{
  1452  			sans: []string{"dns:example.com"},
  1453  			ekus: []string{"msSGC"},
  1454  		},
  1455  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
  1456  		expectedError: "incompatible key usage",
  1457  	},
  1458  
  1459  	// An invalid DNS SAN should be detected only at validation time so
  1460  	// that we can process CA certificates in the wild that have invalid SANs.
  1461  	// See https://github.com/golang/go/issues/23995
  1462  
  1463  	// #77: an invalid DNS or mail SAN will not be detected if name constraint
  1464  	// checking is not triggered.
  1465  	{
  1466  		roots: make([]constraintsSpec, 1),
  1467  		intermediates: [][]constraintsSpec{
  1468  			{
  1469  				{},
  1470  			},
  1471  		},
  1472  		leaf: leafSpec{
  1473  			sans: []string{"dns:this is invalid", "email:this @ is invalid"},
  1474  		},
  1475  	},
  1476  
  1477  	// #78: an invalid DNS SAN will be detected if any name constraint checking
  1478  	// is triggered.
  1479  	{
  1480  		roots: []constraintsSpec{
  1481  			{
  1482  				bad: []string{"uri:"},
  1483  			},
  1484  		},
  1485  		intermediates: [][]constraintsSpec{
  1486  			{
  1487  				{},
  1488  			},
  1489  		},
  1490  		leaf: leafSpec{
  1491  			sans: []string{"dns:this is invalid"},
  1492  		},
  1493  		expectedError: "cannot parse dnsName",
  1494  	},
  1495  
  1496  	// #79: an invalid email SAN will be detected if any name constraint
  1497  	// checking is triggered.
  1498  	{
  1499  		roots: []constraintsSpec{
  1500  			{
  1501  				bad: []string{"uri:"},
  1502  			},
  1503  		},
  1504  		intermediates: [][]constraintsSpec{
  1505  			{
  1506  				{},
  1507  			},
  1508  		},
  1509  		leaf: leafSpec{
  1510  			sans: []string{"email:this @ is invalid"},
  1511  		},
  1512  		expectedError: "cannot parse rfc822Name",
  1513  	},
  1514  
  1515  	// #80: if several EKUs are requested, satisfying any of them is sufficient.
  1516  	{
  1517  		roots: make([]constraintsSpec, 1),
  1518  		intermediates: [][]constraintsSpec{
  1519  			{
  1520  				{},
  1521  			},
  1522  		},
  1523  		leaf: leafSpec{
  1524  			sans: []string{"dns:example.com"},
  1525  			ekus: []string{"email"},
  1526  		},
  1527  		requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
  1528  	},
  1529  
  1530  	// #81: EKUs that are not asserted in VerifyOpts are not required to be
  1531  	// nested.
  1532  	{
  1533  		roots: make([]constraintsSpec, 1),
  1534  		intermediates: [][]constraintsSpec{
  1535  			{
  1536  				{
  1537  					ekus: []string{"serverAuth"},
  1538  				},
  1539  			},
  1540  		},
  1541  		leaf: leafSpec{
  1542  			sans: []string{"dns:example.com"},
  1543  			// There's no email EKU in the intermediate. This would be rejected if
  1544  			// full nesting was required.
  1545  			ekus: []string{"email", "serverAuth"},
  1546  		},
  1547  	},
  1548  
  1549  	// #82: a certificate without SANs and CN is accepted in a constrained chain.
  1550  	{
  1551  		roots: []constraintsSpec{
  1552  			{
  1553  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1554  			},
  1555  		},
  1556  		intermediates: [][]constraintsSpec{
  1557  			{
  1558  				{},
  1559  			},
  1560  		},
  1561  		leaf: leafSpec{
  1562  			sans: []string{},
  1563  		},
  1564  	},
  1565  
  1566  	// #83: a certificate without SANs and with a CN that does not parse as a
  1567  	// hostname is accepted in a constrained chain.
  1568  	{
  1569  		roots: []constraintsSpec{
  1570  			{
  1571  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1572  			},
  1573  		},
  1574  		intermediates: [][]constraintsSpec{
  1575  			{
  1576  				{},
  1577  			},
  1578  		},
  1579  		leaf: leafSpec{
  1580  			sans: []string{},
  1581  			cn:   "foo,bar",
  1582  		},
  1583  	},
  1584  
  1585  	// #84: a certificate with SANs and CN is accepted in a constrained chain.
  1586  	{
  1587  		roots: []constraintsSpec{
  1588  			{
  1589  				ok: []string{"dns:foo.com", "dns:.foo.com"},
  1590  			},
  1591  		},
  1592  		intermediates: [][]constraintsSpec{
  1593  			{
  1594  				{},
  1595  			},
  1596  		},
  1597  		leaf: leafSpec{
  1598  			sans: []string{"dns:foo.com"},
  1599  			cn:   "foo.bar",
  1600  		},
  1601  	},
  1602  
  1603  	// #85: .example.com is an invalid DNS name, it should not match the
  1604  	// constraint example.com.
  1605  	{
  1606  		roots:         []constraintsSpec{{ok: []string{"dns:example.com"}}},
  1607  		leaf:          leafSpec{sans: []string{"dns:.example.com"}},
  1608  		expectedError: "cannot parse dnsName \".example.com\"",
  1609  	},
  1610  }
  1611  
  1612  func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1613  	var serialBytes [16]byte
  1614  	rand.Read(serialBytes[:])
  1615  
  1616  	template := &Certificate{
  1617  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1618  		Subject: pkix.Name{
  1619  			CommonName: name,
  1620  		},
  1621  		NotBefore:             time.Unix(1000, 0),
  1622  		NotAfter:              time.Unix(2000, 0),
  1623  		KeyUsage:              KeyUsageCertSign,
  1624  		BasicConstraintsValid: true,
  1625  		IsCA:                  true,
  1626  	}
  1627  
  1628  	if err := addConstraintsToTemplate(constraints, template); err != nil {
  1629  		return nil, err
  1630  	}
  1631  
  1632  	if parent == nil {
  1633  		parent = template
  1634  	}
  1635  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1636  	if err != nil {
  1637  		return nil, err
  1638  	}
  1639  
  1640  	caCert, err := ParseCertificate(derBytes)
  1641  	if err != nil {
  1642  		return nil, err
  1643  	}
  1644  
  1645  	return caCert, nil
  1646  }
  1647  
  1648  func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1649  	var serialBytes [16]byte
  1650  	rand.Read(serialBytes[:])
  1651  
  1652  	template := &Certificate{
  1653  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1654  		Subject: pkix.Name{
  1655  			OrganizationalUnit: []string{"Leaf"},
  1656  			CommonName:         leaf.cn,
  1657  		},
  1658  		NotBefore:             time.Unix(1000, 0),
  1659  		NotAfter:              time.Unix(2000, 0),
  1660  		KeyUsage:              KeyUsageDigitalSignature,
  1661  		BasicConstraintsValid: true,
  1662  		IsCA:                  false,
  1663  	}
  1664  
  1665  	for _, name := range leaf.sans {
  1666  		switch {
  1667  		case strings.HasPrefix(name, "dns:"):
  1668  			template.DNSNames = append(template.DNSNames, name[4:])
  1669  
  1670  		case strings.HasPrefix(name, "ip:"):
  1671  			ip := net.ParseIP(name[3:])
  1672  			if ip == nil {
  1673  				return nil, fmt.Errorf("cannot parse IP %q", name[3:])
  1674  			}
  1675  			template.IPAddresses = append(template.IPAddresses, ip)
  1676  
  1677  		case strings.HasPrefix(name, "invalidip:"):
  1678  			ipBytes, err := hex.DecodeString(name[10:])
  1679  			if err != nil {
  1680  				return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
  1681  			}
  1682  			template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
  1683  
  1684  		case strings.HasPrefix(name, "email:"):
  1685  			template.EmailAddresses = append(template.EmailAddresses, name[6:])
  1686  
  1687  		case strings.HasPrefix(name, "uri:"):
  1688  			uri, err := url.Parse(name[4:])
  1689  			if err != nil {
  1690  				return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
  1691  			}
  1692  			template.URIs = append(template.URIs, uri)
  1693  
  1694  		case strings.HasPrefix(name, "unknown:"):
  1695  			// This is a special case for testing unknown
  1696  			// name types. A custom SAN extension is
  1697  			// injected into the certificate.
  1698  			if len(leaf.sans) != 1 {
  1699  				panic("when using unknown name types, it must be the sole name")
  1700  			}
  1701  
  1702  			template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
  1703  				Id: []int{2, 5, 29, 17},
  1704  				Value: []byte{
  1705  					0x30, // SEQUENCE
  1706  					3,    // three bytes
  1707  					9,    // undefined GeneralName type 9
  1708  					1,
  1709  					1,
  1710  				},
  1711  			})
  1712  
  1713  		default:
  1714  			return nil, fmt.Errorf("unknown name type %q", name)
  1715  		}
  1716  	}
  1717  
  1718  	var err error
  1719  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
  1720  		return nil, err
  1721  	}
  1722  
  1723  	if parent == nil {
  1724  		parent = template
  1725  	}
  1726  
  1727  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1728  	if err != nil {
  1729  		return nil, err
  1730  	}
  1731  
  1732  	return ParseCertificate(derBytes)
  1733  }
  1734  
  1735  func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
  1736  	appendConstraint := func(contents []byte, tag uint8) []byte {
  1737  		contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
  1738  		contents = append(contents, byte(4+len(constraint)) /* length */)
  1739  		contents = append(contents, 0x30 /* SEQUENCE */)
  1740  		contents = append(contents, byte(2+len(constraint)) /* length */)
  1741  		contents = append(contents, byte(typeNum) /* GeneralName type */)
  1742  		contents = append(contents, byte(len(constraint)))
  1743  		return append(contents, constraint...)
  1744  	}
  1745  
  1746  	var contents []byte
  1747  	if !isExcluded {
  1748  		contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
  1749  	} else {
  1750  		contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
  1751  	}
  1752  
  1753  	var value []byte
  1754  	value = append(value, 0x30 /* SEQUENCE */)
  1755  	value = append(value, byte(len(contents)))
  1756  	value = append(value, contents...)
  1757  
  1758  	return pkix.Extension{
  1759  		Id:    []int{2, 5, 29, 30},
  1760  		Value: value,
  1761  	}
  1762  }
  1763  
  1764  func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
  1765  	parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
  1766  		for _, constraint := range constraints {
  1767  			switch {
  1768  			case strings.HasPrefix(constraint, "dns:"):
  1769  				dnsNames = append(dnsNames, constraint[4:])
  1770  
  1771  			case strings.HasPrefix(constraint, "ip:"):
  1772  				_, ipNet, err := net.ParseCIDR(constraint[3:])
  1773  				if err != nil {
  1774  					return nil, nil, nil, nil, err
  1775  				}
  1776  				ips = append(ips, ipNet)
  1777  
  1778  			case strings.HasPrefix(constraint, "email:"):
  1779  				emailAddrs = append(emailAddrs, constraint[6:])
  1780  
  1781  			case strings.HasPrefix(constraint, "uri:"):
  1782  				uriDomains = append(uriDomains, constraint[4:])
  1783  
  1784  			default:
  1785  				return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
  1786  			}
  1787  		}
  1788  
  1789  		return dnsNames, ips, emailAddrs, uriDomains, err
  1790  	}
  1791  
  1792  	handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
  1793  		switch {
  1794  		case constraint == "unknown:":
  1795  			template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
  1796  
  1797  		default:
  1798  			return false
  1799  		}
  1800  
  1801  		return true
  1802  	}
  1803  
  1804  	if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
  1805  		if handleSpecialConstraint(constraints.ok[0], false) {
  1806  			return nil
  1807  		}
  1808  	}
  1809  
  1810  	if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
  1811  		if handleSpecialConstraint(constraints.bad[0], true) {
  1812  			return nil
  1813  		}
  1814  	}
  1815  
  1816  	var err error
  1817  	template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
  1818  	if err != nil {
  1819  		return err
  1820  	}
  1821  
  1822  	template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
  1823  	if err != nil {
  1824  		return err
  1825  	}
  1826  
  1827  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
  1828  		return err
  1829  	}
  1830  
  1831  	return nil
  1832  }
  1833  
  1834  func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
  1835  	for _, s := range ekuStrs {
  1836  		switch s {
  1837  		case "serverAuth":
  1838  			ekus = append(ekus, ExtKeyUsageServerAuth)
  1839  		case "clientAuth":
  1840  			ekus = append(ekus, ExtKeyUsageClientAuth)
  1841  		case "email":
  1842  			ekus = append(ekus, ExtKeyUsageEmailProtection)
  1843  		case "netscapeSGC":
  1844  			ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
  1845  		case "msSGC":
  1846  			ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
  1847  		case "any":
  1848  			ekus = append(ekus, ExtKeyUsageAny)
  1849  		case "other":
  1850  			unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
  1851  		default:
  1852  			return nil, nil, fmt.Errorf("unknown EKU %q", s)
  1853  		}
  1854  	}
  1855  
  1856  	return
  1857  }
  1858  
  1859  func TestConstraintCases(t *testing.T) {
  1860  	privateKeys := sync.Pool{
  1861  		New: func() any {
  1862  			priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  1863  			if err != nil {
  1864  				panic(err)
  1865  			}
  1866  			return priv
  1867  		},
  1868  	}
  1869  
  1870  	for i, test := range nameConstraintsTests {
  1871  		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  1872  			rootPool := NewCertPool()
  1873  			rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1874  			rootName := "Root " + strconv.Itoa(i)
  1875  
  1876  			// keys keeps track of all the private keys used in a given
  1877  			// test and puts them back in the privateKeys pool at the end.
  1878  			keys := []*ecdsa.PrivateKey{rootKey}
  1879  
  1880  			// At each level (root, intermediate(s), leaf), parent points to
  1881  			// an example parent certificate and parentKey the key for the
  1882  			// parent level. Since all certificates at a given level have
  1883  			// the same name and public key, any parent certificate is
  1884  			// sufficient to get the correct issuer name and authority
  1885  			// key ID.
  1886  			var parent *Certificate
  1887  			parentKey := rootKey
  1888  
  1889  			for _, root := range test.roots {
  1890  				rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
  1891  				if err != nil {
  1892  					t.Fatalf("failed to create root: %s", err)
  1893  				}
  1894  
  1895  				parent = rootCert
  1896  				rootPool.AddCert(rootCert)
  1897  			}
  1898  
  1899  			intermediatePool := NewCertPool()
  1900  
  1901  			for level, intermediates := range test.intermediates {
  1902  				levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1903  				keys = append(keys, levelKey)
  1904  				levelName := "Intermediate level " + strconv.Itoa(level)
  1905  				var last *Certificate
  1906  
  1907  				for _, intermediate := range intermediates {
  1908  					caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
  1909  					if err != nil {
  1910  						t.Fatalf("failed to create %q: %s", levelName, err)
  1911  					}
  1912  
  1913  					last = caCert
  1914  					intermediatePool.AddCert(caCert)
  1915  				}
  1916  
  1917  				parent = last
  1918  				parentKey = levelKey
  1919  			}
  1920  
  1921  			leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1922  			keys = append(keys, leafKey)
  1923  
  1924  			leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
  1925  			if err != nil {
  1926  				t.Fatalf("cannot create leaf: %s", err)
  1927  			}
  1928  
  1929  			// Skip tests with CommonName set because OpenSSL will try to match it
  1930  			// against name constraints, while we ignore it when it's not hostname-looking.
  1931  			if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
  1932  				output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
  1933  				if err == nil && len(test.expectedError) > 0 {
  1934  					t.Error("unexpectedly succeeded against OpenSSL")
  1935  					if debugOpenSSLFailure {
  1936  						return
  1937  					}
  1938  				}
  1939  
  1940  				if err != nil {
  1941  					if _, ok := err.(*exec.ExitError); !ok {
  1942  						t.Errorf("OpenSSL failed to run: %s", err)
  1943  					} else if len(test.expectedError) == 0 {
  1944  						t.Errorf("OpenSSL unexpectedly failed: %v", output)
  1945  						if debugOpenSSLFailure {
  1946  							return
  1947  						}
  1948  					}
  1949  				}
  1950  			}
  1951  
  1952  			verifyOpts := VerifyOptions{
  1953  				Roots:         rootPool,
  1954  				Intermediates: intermediatePool,
  1955  				CurrentTime:   time.Unix(1500, 0),
  1956  				KeyUsages:     test.requestedEKUs,
  1957  			}
  1958  			_, err = leafCert.Verify(verifyOpts)
  1959  
  1960  			logInfo := true
  1961  			if len(test.expectedError) == 0 {
  1962  				if err != nil {
  1963  					t.Errorf("unexpected failure: %s", err)
  1964  				} else {
  1965  					logInfo = false
  1966  				}
  1967  			} else {
  1968  				if err == nil {
  1969  					t.Error("unexpected success")
  1970  				} else if !strings.Contains(err.Error(), test.expectedError) {
  1971  					t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
  1972  				} else {
  1973  					logInfo = false
  1974  				}
  1975  			}
  1976  
  1977  			if logInfo {
  1978  				certAsPEM := func(cert *Certificate) string {
  1979  					var buf bytes.Buffer
  1980  					pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
  1981  					return buf.String()
  1982  				}
  1983  				t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
  1984  				if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
  1985  					for ii, intermediate := range intermediates {
  1986  						t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
  1987  					}
  1988  				}
  1989  				t.Errorf("leaf:\n%s", certAsPEM(leafCert))
  1990  			}
  1991  
  1992  			for _, key := range keys {
  1993  				privateKeys.Put(key)
  1994  			}
  1995  		})
  1996  	}
  1997  }
  1998  
  1999  func writePEMsToTempFile(certs []*Certificate) *os.File {
  2000  	file, err := os.CreateTemp("", "name_constraints_test")
  2001  	if err != nil {
  2002  		panic("cannot create tempfile")
  2003  	}
  2004  
  2005  	pemBlock := &pem.Block{Type: "CERTIFICATE"}
  2006  	for _, cert := range certs {
  2007  		pemBlock.Bytes = cert.Raw
  2008  		pem.Encode(file, pemBlock)
  2009  	}
  2010  
  2011  	return file
  2012  }
  2013  
  2014  func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
  2015  	args := []string{"verify", "-no_check_time"}
  2016  
  2017  	rootsFile := writePEMsToTempFile(allCerts(t, roots))
  2018  	if debugOpenSSLFailure {
  2019  		println("roots file:", rootsFile.Name())
  2020  	} else {
  2021  		defer os.Remove(rootsFile.Name())
  2022  	}
  2023  	args = append(args, "-CAfile", rootsFile.Name())
  2024  
  2025  	if intermediates.len() > 0 {
  2026  		intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
  2027  		if debugOpenSSLFailure {
  2028  			println("intermediates file:", intermediatesFile.Name())
  2029  		} else {
  2030  			defer os.Remove(intermediatesFile.Name())
  2031  		}
  2032  		args = append(args, "-untrusted", intermediatesFile.Name())
  2033  	}
  2034  
  2035  	leafFile := writePEMsToTempFile([]*Certificate{leaf})
  2036  	if debugOpenSSLFailure {
  2037  		println("leaf file:", leafFile.Name())
  2038  	} else {
  2039  		defer os.Remove(leafFile.Name())
  2040  	}
  2041  	args = append(args, leafFile.Name())
  2042  
  2043  	var output bytes.Buffer
  2044  	cmd := exec.Command("openssl", args...)
  2045  	cmd.Stdout = &output
  2046  	cmd.Stderr = &output
  2047  
  2048  	err := cmd.Run()
  2049  	return output.String(), err
  2050  }
  2051  
  2052  var rfc2821Tests = []struct {
  2053  	in                string
  2054  	localPart, domain string
  2055  }{
  2056  	{"foo@example.com", "foo", "example.com"},
  2057  	{"@example.com", "", ""},
  2058  	{"\"@example.com", "", ""},
  2059  	{"\"\"@example.com", "", "example.com"},
  2060  	{"\"a\"@example.com", "a", "example.com"},
  2061  	{"\"\\a\"@example.com", "a", "example.com"},
  2062  	{"a\"@example.com", "", ""},
  2063  	{"foo..bar@example.com", "", ""},
  2064  	{".foo.bar@example.com", "", ""},
  2065  	{"foo.bar.@example.com", "", ""},
  2066  	{"|{}?'@example.com", "|{}?'", "example.com"},
  2067  
  2068  	// Examples from RFC 3696
  2069  	{"Abc\\@def@example.com", "Abc@def", "example.com"},
  2070  	{"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
  2071  	{"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
  2072  	{"\"Abc@def\"@example.com", "Abc@def", "example.com"},
  2073  	{"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
  2074  	{"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
  2075  	{"$A12345@example.com", "$A12345", "example.com"},
  2076  	{"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
  2077  	{"_somename@example.com", "_somename", "example.com"},
  2078  }
  2079  
  2080  func TestRFC2821Parsing(t *testing.T) {
  2081  	for i, test := range rfc2821Tests {
  2082  		mailbox, ok := parseRFC2821Mailbox(test.in)
  2083  		expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
  2084  
  2085  		if ok && expectedFailure {
  2086  			t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
  2087  			continue
  2088  		}
  2089  
  2090  		if !ok && !expectedFailure {
  2091  			t.Errorf("#%d: unexpected failure for %q", i, test.in)
  2092  			continue
  2093  		}
  2094  
  2095  		if !ok {
  2096  			continue
  2097  		}
  2098  
  2099  		if mailbox.local != test.localPart || mailbox.domain != test.domain {
  2100  			t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
  2101  		}
  2102  	}
  2103  }
  2104  
  2105  func TestBadNamesInConstraints(t *testing.T) {
  2106  	constraintParseError := func(err error) bool {
  2107  		str := err.Error()
  2108  		return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
  2109  	}
  2110  
  2111  	encodingError := func(err error) bool {
  2112  		return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
  2113  	}
  2114  
  2115  	// Bad names in constraints should not parse.
  2116  	badNames := []struct {
  2117  		name    string
  2118  		matcher func(error) bool
  2119  	}{
  2120  		{"dns:foo.com.", constraintParseError},
  2121  		{"email:abc@foo.com.", constraintParseError},
  2122  		{"email:foo.com.", constraintParseError},
  2123  		{"uri:example.com.", constraintParseError},
  2124  		{"uri:1.2.3.4", constraintParseError},
  2125  		{"uri:ffff::1", constraintParseError},
  2126  		{"dns:not–hyphen.com", encodingError},
  2127  		{"email:foo@not–hyphen.com", encodingError},
  2128  		{"uri:not–hyphen.com", encodingError},
  2129  	}
  2130  
  2131  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2132  	if err != nil {
  2133  		panic(err)
  2134  	}
  2135  
  2136  	for _, test := range badNames {
  2137  		_, err := makeConstraintsCACert(constraintsSpec{
  2138  			ok: []string{test.name},
  2139  		}, "TestAbsoluteNamesInConstraints", priv, nil, priv)
  2140  
  2141  		if err == nil {
  2142  			t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
  2143  			continue
  2144  		} else {
  2145  			if !test.matcher(err) {
  2146  				t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
  2147  			}
  2148  		}
  2149  	}
  2150  }
  2151  
  2152  func TestBadNamesInSANs(t *testing.T) {
  2153  	// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
  2154  	// will parse and are tested in name constraint tests at the top of this
  2155  	// file.
  2156  	badNames := []string{
  2157  		"uri:https://example.com./dsf",
  2158  		"invalidip:0102",
  2159  		"invalidip:0102030405",
  2160  	}
  2161  
  2162  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2163  	if err != nil {
  2164  		panic(err)
  2165  	}
  2166  
  2167  	for _, badName := range badNames {
  2168  		_, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
  2169  
  2170  		if err == nil {
  2171  			t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
  2172  			continue
  2173  		}
  2174  
  2175  		if str := err.Error(); !strings.Contains(str, "cannot parse ") {
  2176  			t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
  2177  		}
  2178  	}
  2179  }
  2180  

View as plain text