go.uber.org/yarpc@v1.72.1/transport/internal/tls/testscenario/tlsscenario.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package testscenario
    22  
    23  import (
    24  	"crypto/ecdsa"
    25  	"crypto/elliptic"
    26  	"crypto/rand"
    27  	"crypto/tls"
    28  	"crypto/x509"
    29  	"crypto/x509/pkix"
    30  	"math/big"
    31  	"net"
    32  	"testing"
    33  	"time"
    34  
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  // TLSScenario holds client & server tls credentials.
    39  type TLSScenario struct {
    40  	CAs        *x509.CertPool
    41  	ServerCert *x509.Certificate
    42  	ServerKey  *ecdsa.PrivateKey
    43  	ClientCert *x509.Certificate
    44  	ClientKey  *ecdsa.PrivateKey
    45  }
    46  
    47  // ServerTLSConfig returns server TLS config.
    48  func (t TLSScenario) ServerTLSConfig() *tls.Config {
    49  	return &tls.Config{
    50  		GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
    51  			return &tls.Certificate{
    52  				Certificate: [][]byte{t.ServerCert.Raw},
    53  				Leaf:        t.ServerCert,
    54  				PrivateKey:  t.ServerKey,
    55  			}, nil
    56  		},
    57  		ClientAuth: tls.RequireAndVerifyClientCert,
    58  		ClientCAs:  t.CAs,
    59  	}
    60  }
    61  
    62  // ClientTLSConfig returns client TLS config.
    63  func (t TLSScenario) ClientTLSConfig() *tls.Config {
    64  	return &tls.Config{
    65  		GetClientCertificate: func(_ *tls.CertificateRequestInfo) (*tls.Certificate, error) {
    66  			return &tls.Certificate{
    67  				Certificate: [][]byte{t.ClientCert.Raw},
    68  				Leaf:        t.ClientCert,
    69  				PrivateKey:  t.ClientKey,
    70  			}, nil
    71  		},
    72  		ServerName: "127.0.0.1",
    73  		RootCAs:    t.CAs,
    74  	}
    75  }
    76  
    77  // Create returns client and server TLS credentials generated during
    78  // the runtime only for testing.
    79  func Create(t *testing.T, clientValidity time.Duration, serverValidity time.Duration) TLSScenario {
    80  	now := time.Now()
    81  
    82  	caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    83  	require.NoError(t, err)
    84  	caBytes, err := x509.CreateCertificate(
    85  		rand.Reader,
    86  		&x509.Certificate{
    87  			Subject: pkix.Name{
    88  				CommonName: "test ca",
    89  			},
    90  			SerialNumber:          big.NewInt(1),
    91  			BasicConstraintsValid: true,
    92  			IsCA:                  true,
    93  			KeyUsage:              x509.KeyUsageCertSign,
    94  			NotBefore:             now,
    95  			NotAfter:              now.Add(10 * time.Minute),
    96  		},
    97  		&x509.Certificate{},
    98  		caKey.Public(),
    99  		caKey,
   100  	)
   101  	require.NoError(t, err)
   102  	ca, err := x509.ParseCertificate(caBytes)
   103  	require.NoError(t, err)
   104  
   105  	serverKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   106  	require.NoError(t, err)
   107  	serverCertBytes, err := x509.CreateCertificate(
   108  		rand.Reader,
   109  		&x509.Certificate{
   110  			Subject: pkix.Name{
   111  				CommonName: "server",
   112  			},
   113  			NotAfter:     now.Add(serverValidity),
   114  			SerialNumber: big.NewInt(2),
   115  			IPAddresses:  []net.IP{net.ParseIP("127.0.0.1")},
   116  			KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement,
   117  		},
   118  		ca,
   119  		serverKey.Public(),
   120  		caKey,
   121  	)
   122  	require.NoError(t, err)
   123  	serverCert, err := x509.ParseCertificate(serverCertBytes)
   124  	require.NoError(t, err)
   125  
   126  	clientKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   127  	require.NoError(t, err)
   128  	clientCertBytes, err := x509.CreateCertificate(
   129  		rand.Reader,
   130  		&x509.Certificate{
   131  			Subject: pkix.Name{
   132  				CommonName: "client",
   133  			},
   134  			NotAfter:     now.Add(clientValidity),
   135  			SerialNumber: big.NewInt(3),
   136  			KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyAgreement,
   137  		},
   138  		ca,
   139  		clientKey.Public(),
   140  		caKey,
   141  	)
   142  	require.NoError(t, err)
   143  	clientCert, err := x509.ParseCertificate(clientCertBytes)
   144  	require.NoError(t, err)
   145  
   146  	pool := x509.NewCertPool()
   147  	pool.AddCert(ca)
   148  
   149  	return TLSScenario{
   150  		CAs:        pool,
   151  		ServerCert: serverCert,
   152  		ServerKey:  serverKey,
   153  		ClientCert: clientCert,
   154  		ClientKey:  clientKey,
   155  	}
   156  }