9 "github.com/bytom/errors"
10 "github.com/bytom/net"
13 // ErrNoTLS means that no TLS configuration available
14 var ErrNoTLS = errors.New("no TLS configuration available")
16 // TLSConfig returns a TLS config suitable for use
17 // as a bytom client and server.
18 // It reads a PEM-encoded X.509 certificate and private key
19 // from certFile and keyFile.
20 // If rootCAs is given,
21 // it should name a file containing a list of trusted root CA certs,
22 // otherwise the returned config uses the system cert pool.
24 // For compatibility, it attempts to read the cert and key
25 // from the environment if certFile and keyFile both
26 // do not exist in the filesystem.
27 // TLSCRT=[PEM-encoded X.509 certificate]
28 // TLSKEY=[PEM-encoded X.509 private key]
30 // If certFile and keyFile do not exist or are empty
31 // and the environment vars are both unset,
32 // TLSConfig returns ErrNoTLS.
33 func TLSConfig(certFile, keyFile, rootCAs string) (*tls.Config, error) {
34 config := net.DefaultTLSConfig()
36 // This is the default set of protocols for package http.
37 // ListenAndServeTLS and Transport set this automatically,
38 // but since we're supplying our own TLS config,
39 // we have to set it here.
40 // TODO(kr): disabled for now; consider adding h2 support here.
41 // See also the comment on TLSNextProto in $CHAIN/cmd/cored/main.go.
42 //NextProtos: []string{"http/1.1", "h2"},
43 config.ClientAuth = tls.RequestClientCert
45 cert, certErr := ioutil.ReadFile(certFile)
46 key, keyErr := ioutil.ReadFile(keyFile)
47 if os.IsNotExist(certErr) && os.IsNotExist(keyErr) {
48 cert, key = []byte(os.Getenv("TLSCRT")), []byte(os.Getenv("TLSKEY"))
49 } else if certErr != nil {
51 } else if keyErr != nil {
54 if len(cert) == 0 && len(key) == 0 {
59 config.Certificates = make([]tls.Certificate, 1)
60 config.Certificates[0], err = tls.X509KeyPair(cert, key)
62 return nil, errors.Wrap(err)
65 config.RootCAs, err = loadRootCAs(rootCAs)
67 return nil, errors.Wrap(err)
70 // This TLS config is used by cored peers to dial each other,
71 // and by corectl to dial cored.
72 // All those processes have the same identity,
73 // so we automatically trust the local cert,
74 // with the expectation that the peer will also be using it.
75 // This makes misconfiguation impossible.
76 // (For some reason, X509KeyPair doesn't keep a copy of the leaf cert,
77 // so we need to parse it again here.)
78 x509Cert, err := x509.ParseCertificate(config.Certificates[0].Certificate[0])
80 return nil, errors.Wrap(err)
82 config.RootCAs.AddCert(x509Cert)
83 config.ClientCAs = config.RootCAs
87 // loadRootCAs reads a list of PEM-encoded X.509 certificates from name.
88 // If name is the empty string, it returns a new, empty cert pool.
89 func loadRootCAs(name string) (*x509.CertPool, error) {
91 return x509.NewCertPool(), nil
93 pem, err := ioutil.ReadFile(name)
95 return nil, errors.Wrap(err)
97 pool := x509.NewCertPool()
98 ok := pool.AppendCertsFromPEM(pem)
100 return nil, errors.Wrap(errors.New("cannot parse certs"))