nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/internal/test/certs.go (about)

     1  // Copyright 2018 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/rand"
    19  	"crypto/rsa"
    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  	key     *rsa.PrivateKey
    34  	cert    *x509.Certificate
    35  	pair    tls.Certificate
    36  	certDER []byte
    37  
    38  	KeyPEM  []byte // PEM content for private key
    39  	CertPEM []byte // PEM content for certificate
    40  }
    41  
    42  // Keys is a set of the Root, Server, and Client keys for a test config.
    43  type Keys struct {
    44  	Root   KeyPair // Root CA key pair
    45  	Server KeyPair // Server key pair
    46  	Client KeyPair // Client key pair
    47  }
    48  
    49  func (k *KeyPair) genKey(bits int) (err error) {
    50  	if k.key, err = rsa.GenerateKey(rand.Reader, bits); err != nil {
    51  		return
    52  	}
    53  	k.KeyPEM = pem.EncodeToMemory(&pem.Block{
    54  		Type:  "RSA PRIVATE KEY",
    55  		Bytes: x509.MarshalPKCS1PrivateKey(k.key),
    56  	})
    57  	return
    58  }
    59  
    60  func (k *KeyPair) genCert(tmpl *x509.Certificate, parent *KeyPair) (err error) {
    61  	k.cert = tmpl // for self-signed, we pass ourself as parent, this makes it work
    62  	k.certDER, err = x509.CreateCertificate(rand.Reader, tmpl, parent.cert, &k.key.PublicKey, parent.key)
    63  	if err != nil {
    64  		return
    65  	}
    66  	if k.cert, err = x509.ParseCertificate(k.certDER); err != nil {
    67  		return
    68  	}
    69  	k.CertPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: k.certDER})
    70  
    71  	k.pair, err = tls.X509KeyPair(k.CertPEM, k.KeyPEM)
    72  	if err != nil {
    73  		return
    74  	}
    75  	return
    76  }
    77  
    78  func newKeys() (k *Keys, err error) {
    79  	k = &Keys{}
    80  	if err = k.Root.genKey(2048); err != nil {
    81  		return nil, err
    82  	}
    83  	if err = k.Server.genKey(1024); err != nil {
    84  		return nil, err
    85  	}
    86  	if err = k.Client.genKey(1024); err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	if err = k.Root.genCert(rootTmpl, &k.Root); err != nil {
    91  		return nil, err
    92  	}
    93  	if err = k.Server.genCert(serverTmpl, &k.Root); err != nil {
    94  		return nil, err
    95  	}
    96  	if err = k.Client.genCert(clientTmpl, &k.Root); err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	return k, nil
   101  }
   102  
   103  var rootTmpl = &x509.Certificate{
   104  	SerialNumber: big.NewInt(1),
   105  
   106  	Issuer: pkix.Name{
   107  		CommonName:   "issuer.mangos.example.com",
   108  		Organization: []string{"Mangos Issuer Org"},
   109  	},
   110  	Subject: pkix.Name{
   111  		CommonName:   "Root.mangos.example.com",
   112  		Organization: []string{"Mangos Root Org"},
   113  	},
   114  	NotBefore:             time.Unix(1000, 0),
   115  	NotAfter:              time.Now().Add(time.Hour),
   116  	IsCA:                  true,
   117  	BasicConstraintsValid: true,
   118  	OCSPServer:            []string{"ocsp.mangos.example.com"},
   119  	DNSNames:              []string{"Root.mangos.example.com"},
   120  	IPAddresses:           []net.IP{net.ParseIP("127.0.0.1")},
   121  	SignatureAlgorithm:    x509.SHA1WithRSA,
   122  	KeyUsage:              x509.KeyUsageCertSign,
   123  	ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   124  }
   125  
   126  var serverTmpl = &x509.Certificate{
   127  	SerialNumber: big.NewInt(2),
   128  
   129  	Issuer: pkix.Name{
   130  		CommonName:   "issuer.mangos.example.com",
   131  		Organization: []string{"Mangos Issuer Org"},
   132  	},
   133  	Subject: pkix.Name{
   134  		CommonName:   "Server.mangos.example.com",
   135  		Organization: []string{"Mangos Server Org"},
   136  	},
   137  	NotBefore:          time.Unix(1000, 0),
   138  	NotAfter:           time.Now().Add(time.Hour),
   139  	IsCA:               false,
   140  	OCSPServer:         []string{"ocsp.mangos.example.com"},
   141  	DNSNames:           []string{"Server.mangos.example.com"},
   142  	IPAddresses:        []net.IP{net.ParseIP("127.0.0.1")},
   143  	SignatureAlgorithm: x509.SHA1WithRSA,
   144  	KeyUsage:           x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   145  	ExtKeyUsage:        []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   146  }
   147  
   148  var clientTmpl = &x509.Certificate{
   149  	SerialNumber: big.NewInt(3),
   150  
   151  	Issuer: pkix.Name{
   152  		CommonName:   "issuer.mangos.example.com",
   153  		Organization: []string{"Mangos Issuer Org"},
   154  	},
   155  	Subject: pkix.Name{
   156  		CommonName:   "Client.mangos.example.com",
   157  		Organization: []string{"Mangos Client Org"},
   158  	},
   159  	NotBefore:          time.Unix(1000, 0),
   160  	NotAfter:           time.Now().Add(time.Hour),
   161  	IsCA:               false,
   162  	OCSPServer:         []string{"ocsp.mangos.example.com"},
   163  	DNSNames:           []string{"Client.mangos.example.com"},
   164  	IPAddresses:        []net.IP{net.ParseIP("127.0.0.1")},
   165  	SignatureAlgorithm: x509.SHA1WithRSA,
   166  	KeyUsage:           x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   167  	ExtKeyUsage:        []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   168  }
   169  
   170  // NewTLSConfig creates a suitable TLS configuration, using
   171  // either a Server or Client.
   172  func NewTLSConfig() (*tls.Config, *tls.Config, *Keys, error) {
   173  	srvCfg := &tls.Config{}
   174  	cliCfg := &tls.Config{}
   175  
   176  	keys, err := newKeys()
   177  	if err != nil {
   178  		return nil, nil, nil, err
   179  	}
   180  
   181  	// Server side config.
   182  	srvCfg.Certificates = append(srvCfg.Certificates, keys.Server.pair)
   183  
   184  	// Client side config.
   185  	cliCfg.Certificates = append(cliCfg.Certificates, keys.Client.pair)
   186  
   187  	// Now configure the things the Client needs to know -- the self-signed
   188  	// Root CA, and also the Server's identity.
   189  	cliCfg.ServerName = "127.0.0.1"
   190  	cliCfg.RootCAs = x509.NewCertPool()
   191  	cliCfg.RootCAs.AddCert(keys.Root.cert)
   192  	return srvCfg, cliCfg, keys, nil
   193  }
   194  
   195  var lock sync.Mutex
   196  var clientConfig *tls.Config
   197  var serverConfig *tls.Config
   198  var keys *Keys
   199  
   200  // GetTLSConfig is like NewTLSConfig, but it caches to avoid regenerating
   201  // key material pointlessly.
   202  func GetTLSConfig(t *testing.T, server bool) *tls.Config {
   203  	var err error
   204  	lock.Lock()
   205  	defer lock.Unlock()
   206  
   207  	if serverConfig == nil || clientConfig == nil || keys == nil {
   208  		serverConfig, clientConfig, keys, err = NewTLSConfig()
   209  		MustSucceed(t, err)
   210  	}
   211  	if server {
   212  		return serverConfig
   213  	}
   214  	return clientConfig
   215  }
   216  
   217  // GetTLSConfigKeys is like NewTLSConfig, but it caches to avoid regenerating
   218  // key material pointlessly.  It also returns the Keys.
   219  func GetTLSConfigKeys(t *testing.T) (*tls.Config, *tls.Config, *Keys) {
   220  	var err error
   221  	lock.Lock()
   222  	defer lock.Unlock()
   223  
   224  	if serverConfig == nil || clientConfig == nil || keys == nil {
   225  		serverConfig, clientConfig, keys, err = NewTLSConfig()
   226  		MustSucceed(t, err)
   227  	}
   228  	return serverConfig, clientConfig, keys
   229  }