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  	"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  
  1604  func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1605  	var serialBytes [16]byte
  1606  	rand.Read(serialBytes[:])
  1607  
  1608  	template := &Certificate{
  1609  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1610  		Subject: pkix.Name{
  1611  			CommonName: name,
  1612  		},
  1613  		NotBefore:             time.Unix(1000, 0),
  1614  		NotAfter:              time.Unix(2000, 0),
  1615  		KeyUsage:              KeyUsageCertSign,
  1616  		BasicConstraintsValid: true,
  1617  		IsCA:                  true,
  1618  	}
  1619  
  1620  	if err := addConstraintsToTemplate(constraints, template); err != nil {
  1621  		return nil, err
  1622  	}
  1623  
  1624  	if parent == nil {
  1625  		parent = template
  1626  	}
  1627  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1628  	if err != nil {
  1629  		return nil, err
  1630  	}
  1631  
  1632  	caCert, err := ParseCertificate(derBytes)
  1633  	if err != nil {
  1634  		return nil, err
  1635  	}
  1636  
  1637  	return caCert, nil
  1638  }
  1639  
  1640  func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
  1641  	var serialBytes [16]byte
  1642  	rand.Read(serialBytes[:])
  1643  
  1644  	template := &Certificate{
  1645  		SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
  1646  		Subject: pkix.Name{
  1647  			OrganizationalUnit: []string{"Leaf"},
  1648  			CommonName:         leaf.cn,
  1649  		},
  1650  		NotBefore:             time.Unix(1000, 0),
  1651  		NotAfter:              time.Unix(2000, 0),
  1652  		KeyUsage:              KeyUsageDigitalSignature,
  1653  		BasicConstraintsValid: true,
  1654  		IsCA:                  false,
  1655  	}
  1656  
  1657  	for _, name := range leaf.sans {
  1658  		switch {
  1659  		case strings.HasPrefix(name, "dns:"):
  1660  			template.DNSNames = append(template.DNSNames, name[4:])
  1661  
  1662  		case strings.HasPrefix(name, "ip:"):
  1663  			ip := net.ParseIP(name[3:])
  1664  			if ip == nil {
  1665  				return nil, fmt.Errorf("cannot parse IP %q", name[3:])
  1666  			}
  1667  			template.IPAddresses = append(template.IPAddresses, ip)
  1668  
  1669  		case strings.HasPrefix(name, "invalidip:"):
  1670  			ipBytes, err := hex.DecodeString(name[10:])
  1671  			if err != nil {
  1672  				return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
  1673  			}
  1674  			template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
  1675  
  1676  		case strings.HasPrefix(name, "email:"):
  1677  			template.EmailAddresses = append(template.EmailAddresses, name[6:])
  1678  
  1679  		case strings.HasPrefix(name, "uri:"):
  1680  			uri, err := url.Parse(name[4:])
  1681  			if err != nil {
  1682  				return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
  1683  			}
  1684  			template.URIs = append(template.URIs, uri)
  1685  
  1686  		case strings.HasPrefix(name, "unknown:"):
  1687  			// This is a special case for testing unknown
  1688  			// name types. A custom SAN extension is
  1689  			// injected into the certificate.
  1690  			if len(leaf.sans) != 1 {
  1691  				panic("when using unknown name types, it must be the sole name")
  1692  			}
  1693  
  1694  			template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
  1695  				Id: []int{2, 5, 29, 17},
  1696  				Value: []byte{
  1697  					0x30, // SEQUENCE
  1698  					3,    // three bytes
  1699  					9,    // undefined GeneralName type 9
  1700  					1,
  1701  					1,
  1702  				},
  1703  			})
  1704  
  1705  		default:
  1706  			return nil, fmt.Errorf("unknown name type %q", name)
  1707  		}
  1708  	}
  1709  
  1710  	var err error
  1711  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
  1712  		return nil, err
  1713  	}
  1714  
  1715  	if parent == nil {
  1716  		parent = template
  1717  	}
  1718  
  1719  	derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
  1720  	if err != nil {
  1721  		return nil, err
  1722  	}
  1723  
  1724  	return ParseCertificate(derBytes)
  1725  }
  1726  
  1727  func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
  1728  	appendConstraint := func(contents []byte, tag uint8) []byte {
  1729  		contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
  1730  		contents = append(contents, byte(4+len(constraint)) /* length */)
  1731  		contents = append(contents, 0x30 /* SEQUENCE */)
  1732  		contents = append(contents, byte(2+len(constraint)) /* length */)
  1733  		contents = append(contents, byte(typeNum) /* GeneralName type */)
  1734  		contents = append(contents, byte(len(constraint)))
  1735  		return append(contents, constraint...)
  1736  	}
  1737  
  1738  	var contents []byte
  1739  	if !isExcluded {
  1740  		contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
  1741  	} else {
  1742  		contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
  1743  	}
  1744  
  1745  	var value []byte
  1746  	value = append(value, 0x30 /* SEQUENCE */)
  1747  	value = append(value, byte(len(contents)))
  1748  	value = append(value, contents...)
  1749  
  1750  	return pkix.Extension{
  1751  		Id:    []int{2, 5, 29, 30},
  1752  		Value: value,
  1753  	}
  1754  }
  1755  
  1756  func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
  1757  	parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
  1758  		for _, constraint := range constraints {
  1759  			switch {
  1760  			case strings.HasPrefix(constraint, "dns:"):
  1761  				dnsNames = append(dnsNames, constraint[4:])
  1762  
  1763  			case strings.HasPrefix(constraint, "ip:"):
  1764  				_, ipNet, err := net.ParseCIDR(constraint[3:])
  1765  				if err != nil {
  1766  					return nil, nil, nil, nil, err
  1767  				}
  1768  				ips = append(ips, ipNet)
  1769  
  1770  			case strings.HasPrefix(constraint, "email:"):
  1771  				emailAddrs = append(emailAddrs, constraint[6:])
  1772  
  1773  			case strings.HasPrefix(constraint, "uri:"):
  1774  				uriDomains = append(uriDomains, constraint[4:])
  1775  
  1776  			default:
  1777  				return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
  1778  			}
  1779  		}
  1780  
  1781  		return dnsNames, ips, emailAddrs, uriDomains, err
  1782  	}
  1783  
  1784  	handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
  1785  		switch {
  1786  		case constraint == "unknown:":
  1787  			template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
  1788  
  1789  		default:
  1790  			return false
  1791  		}
  1792  
  1793  		return true
  1794  	}
  1795  
  1796  	if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
  1797  		if handleSpecialConstraint(constraints.ok[0], false) {
  1798  			return nil
  1799  		}
  1800  	}
  1801  
  1802  	if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
  1803  		if handleSpecialConstraint(constraints.bad[0], true) {
  1804  			return nil
  1805  		}
  1806  	}
  1807  
  1808  	var err error
  1809  	template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
  1810  	if err != nil {
  1811  		return err
  1812  	}
  1813  
  1814  	template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
  1815  	if err != nil {
  1816  		return err
  1817  	}
  1818  
  1819  	if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
  1820  		return err
  1821  	}
  1822  
  1823  	return nil
  1824  }
  1825  
  1826  func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
  1827  	for _, s := range ekuStrs {
  1828  		switch s {
  1829  		case "serverAuth":
  1830  			ekus = append(ekus, ExtKeyUsageServerAuth)
  1831  		case "clientAuth":
  1832  			ekus = append(ekus, ExtKeyUsageClientAuth)
  1833  		case "email":
  1834  			ekus = append(ekus, ExtKeyUsageEmailProtection)
  1835  		case "netscapeSGC":
  1836  			ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
  1837  		case "msSGC":
  1838  			ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
  1839  		case "any":
  1840  			ekus = append(ekus, ExtKeyUsageAny)
  1841  		case "other":
  1842  			unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
  1843  		default:
  1844  			return nil, nil, fmt.Errorf("unknown EKU %q", s)
  1845  		}
  1846  	}
  1847  
  1848  	return
  1849  }
  1850  
  1851  func TestConstraintCases(t *testing.T) {
  1852  	privateKeys := sync.Pool{
  1853  		New: func() any {
  1854  			priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  1855  			if err != nil {
  1856  				panic(err)
  1857  			}
  1858  			return priv
  1859  		},
  1860  	}
  1861  
  1862  	for i, test := range nameConstraintsTests {
  1863  		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
  1864  			rootPool := NewCertPool()
  1865  			rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1866  			rootName := "Root " + strconv.Itoa(i)
  1867  
  1868  			// keys keeps track of all the private keys used in a given
  1869  			// test and puts them back in the privateKeys pool at the end.
  1870  			keys := []*ecdsa.PrivateKey{rootKey}
  1871  
  1872  			// At each level (root, intermediate(s), leaf), parent points to
  1873  			// an example parent certificate and parentKey the key for the
  1874  			// parent level. Since all certificates at a given level have
  1875  			// the same name and public key, any parent certificate is
  1876  			// sufficient to get the correct issuer name and authority
  1877  			// key ID.
  1878  			var parent *Certificate
  1879  			parentKey := rootKey
  1880  
  1881  			for _, root := range test.roots {
  1882  				rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
  1883  				if err != nil {
  1884  					t.Fatalf("failed to create root: %s", err)
  1885  				}
  1886  
  1887  				parent = rootCert
  1888  				rootPool.AddCert(rootCert)
  1889  			}
  1890  
  1891  			intermediatePool := NewCertPool()
  1892  
  1893  			for level, intermediates := range test.intermediates {
  1894  				levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1895  				keys = append(keys, levelKey)
  1896  				levelName := "Intermediate level " + strconv.Itoa(level)
  1897  				var last *Certificate
  1898  
  1899  				for _, intermediate := range intermediates {
  1900  					caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
  1901  					if err != nil {
  1902  						t.Fatalf("failed to create %q: %s", levelName, err)
  1903  					}
  1904  
  1905  					last = caCert
  1906  					intermediatePool.AddCert(caCert)
  1907  				}
  1908  
  1909  				parent = last
  1910  				parentKey = levelKey
  1911  			}
  1912  
  1913  			leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
  1914  			keys = append(keys, leafKey)
  1915  
  1916  			leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
  1917  			if err != nil {
  1918  				t.Fatalf("cannot create leaf: %s", err)
  1919  			}
  1920  
  1921  			// Skip tests with CommonName set because OpenSSL will try to match it
  1922  			// against name constraints, while we ignore it when it's not hostname-looking.
  1923  			if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
  1924  				output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
  1925  				if err == nil && len(test.expectedError) > 0 {
  1926  					t.Error("unexpectedly succeeded against OpenSSL")
  1927  					if debugOpenSSLFailure {
  1928  						return
  1929  					}
  1930  				}
  1931  
  1932  				if err != nil {
  1933  					if _, ok := err.(*exec.ExitError); !ok {
  1934  						t.Errorf("OpenSSL failed to run: %s", err)
  1935  					} else if len(test.expectedError) == 0 {
  1936  						t.Errorf("OpenSSL unexpectedly failed: %v", output)
  1937  						if debugOpenSSLFailure {
  1938  							return
  1939  						}
  1940  					}
  1941  				}
  1942  			}
  1943  
  1944  			verifyOpts := VerifyOptions{
  1945  				Roots:         rootPool,
  1946  				Intermediates: intermediatePool,
  1947  				CurrentTime:   time.Unix(1500, 0),
  1948  				KeyUsages:     test.requestedEKUs,
  1949  			}
  1950  			_, err = leafCert.Verify(verifyOpts)
  1951  
  1952  			logInfo := true
  1953  			if len(test.expectedError) == 0 {
  1954  				if err != nil {
  1955  					t.Errorf("unexpected failure: %s", err)
  1956  				} else {
  1957  					logInfo = false
  1958  				}
  1959  			} else {
  1960  				if err == nil {
  1961  					t.Error("unexpected success")
  1962  				} else if !strings.Contains(err.Error(), test.expectedError) {
  1963  					t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
  1964  				} else {
  1965  					logInfo = false
  1966  				}
  1967  			}
  1968  
  1969  			if logInfo {
  1970  				certAsPEM := func(cert *Certificate) string {
  1971  					var buf bytes.Buffer
  1972  					pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
  1973  					return buf.String()
  1974  				}
  1975  				t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
  1976  				if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
  1977  					for ii, intermediate := range intermediates {
  1978  						t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
  1979  					}
  1980  				}
  1981  				t.Errorf("leaf:\n%s", certAsPEM(leafCert))
  1982  			}
  1983  
  1984  			for _, key := range keys {
  1985  				privateKeys.Put(key)
  1986  			}
  1987  		})
  1988  	}
  1989  }
  1990  
  1991  func writePEMsToTempFile(certs []*Certificate) *os.File {
  1992  	file, err := os.CreateTemp("", "name_constraints_test")
  1993  	if err != nil {
  1994  		panic("cannot create tempfile")
  1995  	}
  1996  
  1997  	pemBlock := &pem.Block{Type: "CERTIFICATE"}
  1998  	for _, cert := range certs {
  1999  		pemBlock.Bytes = cert.Raw
  2000  		pem.Encode(file, pemBlock)
  2001  	}
  2002  
  2003  	return file
  2004  }
  2005  
  2006  func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
  2007  	args := []string{"verify", "-no_check_time"}
  2008  
  2009  	rootsFile := writePEMsToTempFile(allCerts(t, roots))
  2010  	if debugOpenSSLFailure {
  2011  		println("roots file:", rootsFile.Name())
  2012  	} else {
  2013  		defer os.Remove(rootsFile.Name())
  2014  	}
  2015  	args = append(args, "-CAfile", rootsFile.Name())
  2016  
  2017  	if intermediates.len() > 0 {
  2018  		intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
  2019  		if debugOpenSSLFailure {
  2020  			println("intermediates file:", intermediatesFile.Name())
  2021  		} else {
  2022  			defer os.Remove(intermediatesFile.Name())
  2023  		}
  2024  		args = append(args, "-untrusted", intermediatesFile.Name())
  2025  	}
  2026  
  2027  	leafFile := writePEMsToTempFile([]*Certificate{leaf})
  2028  	if debugOpenSSLFailure {
  2029  		println("leaf file:", leafFile.Name())
  2030  	} else {
  2031  		defer os.Remove(leafFile.Name())
  2032  	}
  2033  	args = append(args, leafFile.Name())
  2034  
  2035  	var output bytes.Buffer
  2036  	cmd := exec.Command("openssl", args...)
  2037  	cmd.Stdout = &output
  2038  	cmd.Stderr = &output
  2039  
  2040  	err := cmd.Run()
  2041  	return output.String(), err
  2042  }
  2043  
  2044  var rfc2821Tests = []struct {
  2045  	in                string
  2046  	localPart, domain string
  2047  }{
  2048  	{"foo@example.com", "foo", "example.com"},
  2049  	{"@example.com", "", ""},
  2050  	{"\"@example.com", "", ""},
  2051  	{"\"\"@example.com", "", "example.com"},
  2052  	{"\"a\"@example.com", "a", "example.com"},
  2053  	{"\"\\a\"@example.com", "a", "example.com"},
  2054  	{"a\"@example.com", "", ""},
  2055  	{"foo..bar@example.com", "", ""},
  2056  	{".foo.bar@example.com", "", ""},
  2057  	{"foo.bar.@example.com", "", ""},
  2058  	{"|{}?'@example.com", "|{}?'", "example.com"},
  2059  
  2060  	// Examples from RFC 3696
  2061  	{"Abc\\@def@example.com", "Abc@def", "example.com"},
  2062  	{"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
  2063  	{"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
  2064  	{"\"Abc@def\"@example.com", "Abc@def", "example.com"},
  2065  	{"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
  2066  	{"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
  2067  	{"$A12345@example.com", "$A12345", "example.com"},
  2068  	{"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
  2069  	{"_somename@example.com", "_somename", "example.com"},
  2070  }
  2071  
  2072  func TestRFC2821Parsing(t *testing.T) {
  2073  	for i, test := range rfc2821Tests {
  2074  		mailbox, ok := parseRFC2821Mailbox(test.in)
  2075  		expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
  2076  
  2077  		if ok && expectedFailure {
  2078  			t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
  2079  			continue
  2080  		}
  2081  
  2082  		if !ok && !expectedFailure {
  2083  			t.Errorf("#%d: unexpected failure for %q", i, test.in)
  2084  			continue
  2085  		}
  2086  
  2087  		if !ok {
  2088  			continue
  2089  		}
  2090  
  2091  		if mailbox.local != test.localPart || mailbox.domain != test.domain {
  2092  			t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
  2093  		}
  2094  	}
  2095  }
  2096  
  2097  func TestBadNamesInConstraints(t *testing.T) {
  2098  	constraintParseError := func(err error) bool {
  2099  		str := err.Error()
  2100  		return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
  2101  	}
  2102  
  2103  	encodingError := func(err error) bool {
  2104  		return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
  2105  	}
  2106  
  2107  	// Bad names in constraints should not parse.
  2108  	badNames := []struct {
  2109  		name    string
  2110  		matcher func(error) bool
  2111  	}{
  2112  		{"dns:foo.com.", constraintParseError},
  2113  		{"email:abc@foo.com.", constraintParseError},
  2114  		{"email:foo.com.", constraintParseError},
  2115  		{"uri:example.com.", constraintParseError},
  2116  		{"uri:1.2.3.4", constraintParseError},
  2117  		{"uri:ffff::1", constraintParseError},
  2118  		{"dns:not–hyphen.com", encodingError},
  2119  		{"email:foo@not–hyphen.com", encodingError},
  2120  		{"uri:not–hyphen.com", encodingError},
  2121  	}
  2122  
  2123  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2124  	if err != nil {
  2125  		panic(err)
  2126  	}
  2127  
  2128  	for _, test := range badNames {
  2129  		_, err := makeConstraintsCACert(constraintsSpec{
  2130  			ok: []string{test.name},
  2131  		}, "TestAbsoluteNamesInConstraints", priv, nil, priv)
  2132  
  2133  		if err == nil {
  2134  			t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
  2135  			continue
  2136  		} else {
  2137  			if !test.matcher(err) {
  2138  				t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
  2139  			}
  2140  		}
  2141  	}
  2142  }
  2143  
  2144  func TestBadNamesInSANs(t *testing.T) {
  2145  	// Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
  2146  	// will parse and are tested in name constraint tests at the top of this
  2147  	// file.
  2148  	badNames := []string{
  2149  		"uri:https://example.com./dsf",
  2150  		"invalidip:0102",
  2151  		"invalidip:0102030405",
  2152  	}
  2153  
  2154  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  2155  	if err != nil {
  2156  		panic(err)
  2157  	}
  2158  
  2159  	for _, badName := range badNames {
  2160  		_, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
  2161  
  2162  		if err == nil {
  2163  			t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
  2164  			continue
  2165  		}
  2166  
  2167  		if str := err.Error(); !strings.Contains(str, "cannot parse ") {
  2168  			t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
  2169  		}
  2170  	}
  2171  }
  2172  

View as plain text