go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/internal/test/certs.go (about)

     1  // Copyright 2022 The Mangos Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use file except in compliance with the License.
     5  // You may obtain a copy of the license at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES O R CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package test
    16  
    17  import (
    18  	"crypto/ed25519"
    19  	"crypto/rand"
    20  	"crypto/tls"
    21  	"crypto/x509"
    22  	"crypto/x509/pkix"
    23  	"encoding/pem"
    24  	"math/big"
    25  	"net"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  )
    30  
    31  // KeyPair is a single public key pair
    32  type KeyPair struct {
    33  	cert    *x509.Certificate
    34  	pair    tls.Certificate
    35  	certDER []byte
    36  	pubKey  ed25519.PublicKey
    37  	prvKey  ed25519.PrivateKey
    38  }
    39  
    40  // Keys is a set of the Root, Server, and Client keys for a test config.
    41  type Keys struct {
    42  	Root   KeyPair // Root CA key pair
    43  	Server KeyPair // Server key pair
    44  	Client KeyPair // Client key pair
    45  }
    46  
    47  func (k *KeyPair) CertPEM() []byte {
    48  	return pem.EncodeToMemory(&pem.Block{
    49  		Type:    "CERTIFICATE",
    50  		Headers: nil,
    51  		Bytes:   k.certDER,
    52  	})
    53  }
    54  
    55  func (k *KeyPair) KeyPEM() []byte {
    56  
    57  	b, err := x509.MarshalPKCS8PrivateKey(k.prvKey)
    58  	if err != nil {
    59  		return nil
    60  	}
    61  
    62  	return pem.EncodeToMemory(&pem.Block{
    63  		Type:  "PRIVATE KEY",
    64  		Bytes: b,
    65  	})
    66  }
    67  
    68  func (k *KeyPair) PubKeyPEM() []byte {
    69  	b, err := x509.MarshalPKIXPublicKey(k.pubKey)
    70  	if err != nil {
    71  		return nil
    72  	}
    73  
    74  	return pem.EncodeToMemory(&pem.Block{
    75  		Type:  "PUBLIC KEY",
    76  		Bytes: b,
    77  	})
    78  }
    79  
    80  func (k *KeyPair) genKey() (err error) {
    81  	if k.pubKey, k.prvKey, err = ed25519.GenerateKey(rand.Reader); err != nil {
    82  		return
    83  	}
    84  	return
    85  }
    86  
    87  func (k *KeyPair) genCert(tmpl *x509.Certificate, parent *KeyPair) (err error) {
    88  	k.cert = tmpl // for self-signed, we pass ourselves as parent, this makes it work
    89  	k.certDER, err = x509.CreateCertificate(rand.Reader, tmpl, parent.cert, k.pubKey, parent.prvKey)
    90  	if err != nil {
    91  		return
    92  	}
    93  	if k.cert, err = x509.ParseCertificate(k.certDER); err != nil {
    94  		return
    95  	}
    96  	k.pair = tls.Certificate{
    97  		Certificate: [][]byte{k.certDER},
    98  		PrivateKey:  k.prvKey,
    99  		Leaf:        k.cert,
   100  	}
   101  	return
   102  }
   103  
   104  func newKeys() (k *Keys, err error) {
   105  	k = &Keys{}
   106  	if err = k.Root.genKey(); err != nil {
   107  		return nil, err
   108  	}
   109  	if err = k.Server.genKey(); err != nil {
   110  		return nil, err
   111  	}
   112  	if err = k.Client.genKey(); err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	if err = k.Root.genCert(rootTmpl, &k.Root); err != nil {
   117  		return nil, err
   118  	}
   119  	if err = k.Server.genCert(serverTmpl, &k.Root); err != nil {
   120  		return nil, err
   121  	}
   122  	if err = k.Client.genCert(clientTmpl, &k.Root); err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	return k, nil
   127  }
   128  
   129  var rootTmpl = &x509.Certificate{
   130  	SerialNumber: big.NewInt(1),
   131  
   132  	Issuer: pkix.Name{
   133  		CommonName:   "issuer.mangos.example.com",
   134  		Organization: []string{"Mangos Issuer Org"},
   135  	},
   136  	Subject: pkix.Name{
   137  		CommonName:   "Root.mangos.example.com",
   138  		Organization: []string{"Mangos Root Org"},
   139  	},
   140  	NotBefore:             time.Unix(1000, 0),
   141  	NotAfter:              time.Now().Add(time.Hour),
   142  	IsCA:                  true,
   143  	BasicConstraintsValid: true,
   144  	OCSPServer:            []string{"ocsp.mangos.example.com"},
   145  	DNSNames:              []string{"Root.mangos.example.com"},
   146  	IPAddresses:           []net.IP{net.ParseIP("127.0.0.1")},
   147  	SignatureAlgorithm:    x509.PureEd25519,
   148  	KeyUsage:              x509.KeyUsageCertSign,
   149  	ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   150  }
   151  
   152  var serverTmpl = &x509.Certificate{
   153  	SerialNumber: big.NewInt(2),
   154  
   155  	Issuer: pkix.Name{
   156  		CommonName:   "issuer.mangos.example.com",
   157  		Organization: []string{"Mangos Issuer Org"},
   158  	},
   159  	Subject: pkix.Name{
   160  		CommonName:   "Server.mangos.example.com",
   161  		Organization: []string{"Mangos Server Org"},
   162  	},
   163  	NotBefore:          time.Unix(1000, 0),
   164  	NotAfter:           time.Now().Add(time.Hour),
   165  	IsCA:               false,
   166  	OCSPServer:         []string{"ocsp.mangos.example.com"},
   167  	DNSNames:           []string{"Server.mangos.example.com"},
   168  	IPAddresses:        []net.IP{net.ParseIP("127.0.0.1")},
   169  	SignatureAlgorithm: x509.PureEd25519,
   170  	KeyUsage:           x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   171  	ExtKeyUsage:        []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   172  }
   173  
   174  var clientTmpl = &x509.Certificate{
   175  	SerialNumber: big.NewInt(3),
   176  
   177  	Issuer: pkix.Name{
   178  		CommonName:   "issuer.mangos.example.com",
   179  		Organization: []string{"Mangos Issuer Org"},
   180  	},
   181  	Subject: pkix.Name{
   182  		CommonName:   "Client.mangos.example.com",
   183  		Organization: []string{"Mangos Client Org"},
   184  	},
   185  	NotBefore:          time.Unix(1000, 0),
   186  	NotAfter:           time.Now().Add(time.Hour),
   187  	IsCA:               false,
   188  	OCSPServer:         []string{"ocsp.mangos.example.com"},
   189  	DNSNames:           []string{"Client.mangos.example.com"},
   190  	IPAddresses:        []net.IP{net.ParseIP("127.0.0.1")},
   191  	SignatureAlgorithm: x509.PureEd25519,
   192  	KeyUsage:           x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   193  	ExtKeyUsage:        []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   194  }
   195  
   196  // NewTLSConfig creates a suitable TLS configuration, using
   197  // either a Server or Client.
   198  func NewTLSConfig() (*tls.Config, *tls.Config, *Keys, error) {
   199  	srvCfg := &tls.Config{}
   200  	cliCfg := &tls.Config{}
   201  
   202  	keys, err := newKeys()
   203  	if err != nil {
   204  		return nil, nil, nil, err
   205  	}
   206  
   207  	// Server side config.
   208  	srvCfg.Certificates = append(srvCfg.Certificates, keys.Server.pair)
   209  
   210  	// Client side config.
   211  	cliCfg.Certificates = append(cliCfg.Certificates, keys.Client.pair)
   212  
   213  	// Now configure the things the Client needs to know -- the self-signed
   214  	// Root CA, and also the Server's identity.
   215  	cliCfg.ServerName = "127.0.0.1"
   216  	cliCfg.RootCAs = x509.NewCertPool()
   217  	cliCfg.RootCAs.AddCert(keys.Root.cert)
   218  	return srvCfg, cliCfg, keys, nil
   219  }
   220  
   221  var lock sync.Mutex
   222  var clientConfig *tls.Config
   223  var serverConfig *tls.Config
   224  var keys *Keys
   225  
   226  // GetTLSConfig is like NewTLSConfig, but it caches to avoid regenerating
   227  // key material pointlessly.
   228  func GetTLSConfig(t *testing.T, server bool) *tls.Config {
   229  	var err error
   230  	lock.Lock()
   231  	defer lock.Unlock()
   232  
   233  	if serverConfig == nil || clientConfig == nil || keys == nil {
   234  		serverConfig, clientConfig, keys, err = NewTLSConfig()
   235  		MustSucceed(t, err)
   236  	}
   237  	if server {
   238  		return serverConfig
   239  	}
   240  	return clientConfig
   241  }
   242  
   243  // GetTLSConfigKeys is like NewTLSConfig, but it caches to avoid regenerating
   244  // key material pointlessly.  It also returns the Keys.
   245  func GetTLSConfigKeys(t *testing.T) (*tls.Config, *tls.Config, *Keys) {
   246  	var err error
   247  	lock.Lock()
   248  	defer lock.Unlock()
   249  
   250  	if serverConfig == nil || clientConfig == nil || keys == nil {
   251  		serverConfig, clientConfig, keys, err = NewTLSConfig()
   252  		MustSucceed(t, err)
   253  	}
   254  	return serverConfig, clientConfig, keys
   255  }