github.com/Psiphon-Labs/tls-tris@v0.0.0-20230824155421-58bf6d336a9a/subcerts_test.go (about)

     1  // Copyright 2018 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 tls
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/x509"
    10  	"encoding/asn1"
    11  	"encoding/pem"
    12  	"errors"
    13  	"fmt"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  // A PEM-encoded "delegation certificate", an X.509 certificate with the
    19  // DelegationUsage extension. The extension is defined in
    20  // specified in https://tools.ietf.org/html/draft-ietf-tls-subcerts-02.
    21  const DcCertWithDelegationUsage = `-----BEGIN CERTIFICATE-----
    22  MIIBejCCASGgAwIBAgIQXXtl0v50W2OadoW0QwLUlzAKBggqhkjOPQQDAjAUMRIw
    23  EAYDVQQKEwlBY21lIEluYy4wHhcNMTgwNzMwMjAxMTE5WhcNMTgwODA2MjAxMTE5
    24  WjAUMRIwEAYDVQQKEwlBY21lIEluYy4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
    25  AATcQuuaUNJ3kqKGs4DBdJVd7zWzyGANT4uBNGVkZ2cgaDsdFnx99fGibfgoWer8
    26  HLt9Z+S6Hs+8bDPBHNgTR/Lfo1UwUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww
    27  CgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwR/AAABMA0GCSsG
    28  AQQBgtpLLAQAMAoGCCqGSM49BAMCA0cAMEQCIEMdIkwwmzQAJ6RSDT3wcrsySx2B
    29  5Lvx5HGzc43Fgu9eAiAi4sFXnizFBVUL43qXZBq4ARw17o0JW3/7eec1xttQhw==
    30  -----END CERTIFICATE-----
    31  `
    32  
    33  // The PEM-encoded "delegation key", the secret key associated with the
    34  // delegation certificate. This is a key for ECDSA with P256 and SHA256.
    35  const DcKeyWithDelegationUsage = `-----BEGIN EC PRIVATE KEY-----
    36  MHcCAQEEIAS/pGktmxK1hlt3gF4N2nkMrJnoZihvOO63nnNcxXQroAoGCCqGSM49
    37  AwEHoUQDQgAE3ELrmlDSd5KihrOAwXSVXe81s8hgDU+LgTRlZGdnIGg7HRZ8ffXx
    38  om34KFnq/By7fWfkuh7PvGwzwRzYE0fy3w==
    39  -----END EC PRIVATE KEY-----
    40  `
    41  
    42  // A certificate without the DelegationUsage extension.
    43  const DcCertWithoutDelegationUsage = `-----BEGIN CERTIFICATE-----
    44  MIIBajCCAQ+gAwIBAgIRAMUg/VFqJaWWJwZ9iHoMjqIwCgYIKoZIzj0EAwIwEjEQ
    45  MA4GA1UEChMHQWNtZSBDbzAeFw0xODA3MzAyMDExMTlaFw0xOTA3MzAyMDExMTla
    46  MBIxEDAOBgNVBAoTB0FjbWUgQ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATA
    47  n+oeWSvSNHhEskSRgkkerCQDoV/NA+r3S5AtCOFT5AYLt8xltSTWerFI/YlZLIcL
    48  xlJPT7T+XpBnfS6xaAuxo0YwRDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI
    49  KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwR/AAABMAoGCCqGSM49
    50  BAMCA0kAMEYCIQCFGWnoJmwH1rxNCKBJWVDBKDTSsYhySRk4h9RPyR8bUwIhAJxc
    51  KFyrowMTan791RJnyANH/4uYhmvkfhfrFGSTXUli
    52  -----END CERTIFICATE-----
    53  `
    54  
    55  // The secret key associatted with DcCertWithoutDelegationUsage.
    56  const DcKeyWithoutDelegationUsage = `-----BEGIN EC PRIVATE KEY-----
    57  MHcCAQEEIEP82pOhzx0tKkky9t0OmUo9MHgmfdAHxDN2cHmWGqOhoAoGCCqGSM49
    58  AwEHoUQDQgAEwJ/qHlkr0jR4RLJEkYJJHqwkA6FfzQPq90uQLQjhU+QGC7fMZbUk
    59  1nqxSP2JWSyHC8ZST0+0/l6QZ30usWgLsQ==
    60  -----END EC PRIVATE KEY-----
    61  `
    62  
    63  // dcTestDC stores delegated credentials and their secret keys.
    64  type dcTestDC struct {
    65  	Name       string
    66  	Version    int
    67  	Scheme     int
    68  	DC         []byte
    69  	PrivateKey []byte
    70  }
    71  
    72  // Use with maxVersion == VersionTLS13.
    73  const DcTestDataTLS13PEM = `-----BEGIN DC TEST DATA-----
    74  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
   118  jreml8HfVQ==
   119  -----END DC TEST DATA-----`
   120  
   121  // Parses the input PEM block containing the test DCs.
   122  func dcLoadTestData(in []byte, out *[]dcTestDC) error {
   123  	block, _ := pem.Decode(in)
   124  	if block == nil {
   125  		return errors.New("failed to decode DC tests PEM block")
   126  	}
   127  
   128  	// Parse the DER-encoded test DCs.
   129  	_, err := asn1.Unmarshal(block.Bytes, out)
   130  	if err != nil {
   131  		return errors.New("failed to unmarshal DC test ASN.1 data")
   132  	}
   133  
   134  	// Check that the test data is for the right version. This should be
   135  	// maxVersion, defined in common.go.
   136  	for _, test := range *out {
   137  		dc, err := unmarshalDelegatedCredential(test.DC)
   138  		if err != nil {
   139  			return err
   140  		}
   141  
   142  		// Sanity check that test version matches the version encoded by the DC.
   143  		testVersion := uint16(test.Version)
   144  		if dc.cred.expectedVersion != testVersion {
   145  			return fmt.Errorf(
   146  				"test version doesn't match credential version: got: 0x0%04x; want: 0x%04x",
   147  				testVersion, dc.cred.expectedVersion)
   148  		}
   149  
   150  		// With the exception of "badvers" and "tsl12", all test DCs should have
   151  		// the expected verison.
   152  		if test.Name != "badvers" && test.Name != "tls12" && testVersion != maxVersion {
   153  			return fmt.Errorf(
   154  				"encountered test with wrong version: got: 0x0%04x; want: 0x%04x",
   155  				test.Version, maxVersion)
   156  		}
   157  	}
   158  	return nil
   159  }
   160  
   161  var dcTestDCs []dcTestDC
   162  var dcTestConfig *Config
   163  var dcTestDelegationCert Certificate
   164  var dcTestCert Certificate
   165  var dcTestNow time.Time
   166  
   167  func init() {
   168  	// Load the DC test data.
   169  	var testData []byte
   170  	if maxVersion != 0x0304 {
   171  		panic(fmt.Errorf("no test data for version %04x", maxVersion))
   172  	}
   173  	testData = []byte(DcTestDataTLS13PEM)
   174  
   175  	err := dcLoadTestData(testData, &dcTestDCs)
   176  	if err != nil {
   177  		panic(err)
   178  	}
   179  
   180  	// The base configuration for the client and server.
   181  	dcTestConfig = &Config{
   182  		Time: func() time.Time {
   183  			return dcTestNow
   184  		},
   185  		Rand:         zeroSource{},
   186  		Certificates: nil,
   187  		MinVersion:   VersionTLS10,
   188  		MaxVersion:   VersionTLS13,
   189  		CipherSuites: allCipherSuites(),
   190  	}
   191  
   192  	// The delegation certificate.
   193  	dcTestDelegationCert, err = X509KeyPair([]byte(DcCertWithDelegationUsage), []byte(DcKeyWithDelegationUsage))
   194  	if err != nil {
   195  		panic(err)
   196  	}
   197  	dcTestDelegationCert.Leaf, err = x509.ParseCertificate(dcTestDelegationCert.Certificate[0])
   198  	if err != nil {
   199  		panic(err)
   200  	}
   201  
   202  	// A certificate without the the DelegationUsage extension for X.509.
   203  	dcTestCert, err = X509KeyPair([]byte(DcCertWithoutDelegationUsage), []byte(DcKeyWithoutDelegationUsage))
   204  	if err != nil {
   205  		panic(err)
   206  	}
   207  	dcTestCert.Leaf, err = x509.ParseCertificate(dcTestCert.Certificate[0])
   208  	if err != nil {
   209  		panic(err)
   210  	}
   211  
   212  	// For testing purposes, use the point at which the test DCs were generated
   213  	// as the current time.  This is the same as the time at which the
   214  	// delegation certificate was generated.
   215  	dcTestNow = dcTestDelegationCert.Leaf.NotBefore
   216  
   217  	// Make these roots of these certificates the client's trusted CAs.
   218  	dcTestConfig.RootCAs = x509.NewCertPool()
   219  
   220  	raw := dcTestDelegationCert.Certificate[len(dcTestDelegationCert.Certificate)-1]
   221  	root, err := x509.ParseCertificate(raw)
   222  	if err != nil {
   223  		panic(err)
   224  	}
   225  	dcTestConfig.RootCAs.AddCert(root)
   226  
   227  	raw = dcTestCert.Certificate[len(dcTestCert.Certificate)-1]
   228  	root, err = x509.ParseCertificate(raw)
   229  	if err != nil {
   230  		panic(err)
   231  	}
   232  	dcTestConfig.RootCAs.AddCert(root)
   233  }
   234  
   235  // Executes the handshake with the given configuration and returns true if the
   236  // delegated credential extension was successfully negotiated.
   237  func testConnWithDC(t *testing.T, clientConfig, serverConfig *Config) (bool, error) {
   238  	ln := newLocalListener(t)
   239  	defer ln.Close()
   240  
   241  	// Listen for and serve a single client connection.
   242  	srvCh := make(chan *Conn, 1)
   243  	var serr error
   244  	go func() {
   245  		sconn, err := ln.Accept()
   246  		if err != nil {
   247  			serr = err
   248  			srvCh <- nil
   249  			return
   250  		}
   251  		srv := Server(sconn, serverConfig)
   252  		if err := srv.Handshake(); err != nil {
   253  			serr = fmt.Errorf("handshake: %v", err)
   254  			srvCh <- nil
   255  			return
   256  		}
   257  		srvCh <- srv
   258  	}()
   259  
   260  	// Dial the server.
   261  	cli, err := Dial("tcp", ln.Addr().String(), clientConfig)
   262  	if err != nil {
   263  		return false, err
   264  	}
   265  	defer cli.Close()
   266  
   267  	srv := <-srvCh
   268  	if srv == nil {
   269  		return false, serr
   270  	}
   271  
   272  	// Return true if the client's conn.dc structure was instantiated.
   273  	st := cli.ConnectionState()
   274  	return (st.DelegatedCredential != nil), nil
   275  }
   276  
   277  // Checks that the client suppports a version >= 1.2 and accepts delegated
   278  // credentials. If so, it returns the delegation certificate; otherwise it
   279  // returns a plain certificate.
   280  func testServerGetCertificate(ch *ClientHelloInfo) (*Certificate, error) {
   281  	versOk := false
   282  	for _, vers := range ch.SupportedVersions {
   283  		versOk = versOk || (vers >= uint16(VersionTLS12))
   284  	}
   285  
   286  	if versOk && ch.AcceptsDelegatedCredential {
   287  		return &dcTestDelegationCert, nil
   288  	}
   289  	return &dcTestCert, nil
   290  }
   291  
   292  // Various test cases for handshakes involving DCs.
   293  var dcTesters = []struct {
   294  	clientDC         bool
   295  	serverDC         bool
   296  	clientSkipVerify bool
   297  	clientMaxVers    uint16
   298  	serverMaxVers    uint16
   299  	nowOffset        time.Duration
   300  	dcTestName       string
   301  	expectSuccess    bool
   302  	expectDC         bool
   303  	name             string
   304  }{
   305  	{true, true, false, VersionTLS13, VersionTLS13, 0, "tls13p256", true, true, "tls13"},
   306  	{true, true, false, VersionTLS13, VersionTLS13, 0, "tls13p521", true, true, "tls13"},
   307  	{true, false, false, VersionTLS13, VersionTLS13, 0, "tls13p256", true, false, "server no dc"},
   308  	{true, true, false, VersionTLS12, VersionTLS13, 0, "tls13p256", true, false, "client old"},
   309  	{true, true, false, VersionTLS13, VersionTLS12, 0, "tls13p256", true, false, "server old"},
   310  	{true, true, false, VersionTLS13, VersionTLS13, 0, "badkey", false, false, "bad key"},
   311  	{true, true, true, VersionTLS13, VersionTLS13, 0, "badsig", true, true, "bad key, skip verify"},
   312  	{true, true, false, VersionTLS13, VersionTLS13, dcMaxTTL, "tls13", false, false, "expired dc"},
   313  	{true, true, false, VersionTLS13, VersionTLS13, 0, "badvers", false, false, "dc wrong version"},
   314  	{true, true, false, VersionTLS12, VersionTLS12, 0, "tls12", true, false, "tls12"},
   315  }
   316  
   317  // Tests the handshake with the delegated credential extension for each test
   318  // case in dcTests.
   319  func TestDCHandshake(t *testing.T) {
   320  	clientConfig := dcTestConfig.Clone()
   321  	serverConfig := dcTestConfig.Clone()
   322  	serverConfig.GetCertificate = testServerGetCertificate
   323  
   324  	for i, tester := range dcTesters {
   325  		clientConfig.MaxVersion = tester.clientMaxVers
   326  		serverConfig.MaxVersion = tester.serverMaxVers
   327  		clientConfig.InsecureSkipVerify = tester.clientSkipVerify
   328  		clientConfig.AcceptDelegatedCredential = tester.clientDC
   329  		clientConfig.Time = func() time.Time {
   330  			return dcTestNow.Add(time.Duration(tester.nowOffset))
   331  		}
   332  
   333  		if tester.serverDC {
   334  			serverConfig.GetDelegatedCredential = func(
   335  				ch *ClientHelloInfo, vers uint16) ([]byte, crypto.PrivateKey, error) {
   336  				if vers < VersionTLS13 {
   337  					return nil, nil, nil
   338  				}
   339  				for _, test := range dcTestDCs {
   340  					if test.Name == tester.dcTestName {
   341  						sk, err := x509.ParseECPrivateKey(test.PrivateKey)
   342  						if err != nil {
   343  							return nil, nil, err
   344  						}
   345  						return test.DC, sk, nil
   346  					}
   347  				}
   348  				return nil, nil, fmt.Errorf("Test DC with name '%s' not found", tester.dcTestName)
   349  			}
   350  		} else {
   351  			serverConfig.GetDelegatedCredential = nil
   352  		}
   353  
   354  		usedDC, err := testConnWithDC(t, clientConfig, serverConfig)
   355  		if err != nil && tester.expectSuccess {
   356  			t.Errorf("test #%d (%s) fails: %s", i+1, tester.name, err)
   357  		} else if err == nil && !tester.expectSuccess {
   358  			t.Errorf("test #%d (%s) succeeds; expected failure", i+1, tester.name)
   359  		}
   360  
   361  		if usedDC != tester.expectDC {
   362  			t.Errorf("test #%d (%s) usedDC = %v; expected %v", i+1, tester.name, usedDC, tester.expectDC)
   363  		}
   364  	}
   365  }