OSDN Git Service

update master (#487)
[bytom/bytom-spv.git] / blockchain / tls.go
1 package blockchain
2
3 import (
4         "crypto/tls"
5         "crypto/x509"
6         "io/ioutil"
7         "os"
8
9         "github.com/bytom/errors"
10         "github.com/bytom/net"
11 )
12
13 // ErrNoTLS means that no TLS configuration available
14 var ErrNoTLS = errors.New("no TLS configuration available")
15
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.
23 //
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]
29 //
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()
35
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
44
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 {
50                 return nil, certErr
51         } else if keyErr != nil {
52                 return nil, keyErr
53         }
54         if len(cert) == 0 && len(key) == 0 {
55                 return nil, ErrNoTLS
56         }
57
58         var err error
59         config.Certificates = make([]tls.Certificate, 1)
60         config.Certificates[0], err = tls.X509KeyPair(cert, key)
61         if err != nil {
62                 return nil, errors.Wrap(err)
63         }
64
65         config.RootCAs, err = loadRootCAs(rootCAs)
66         if err != nil {
67                 return nil, errors.Wrap(err)
68         }
69
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])
79         if err != nil {
80                 return nil, errors.Wrap(err)
81         }
82         config.RootCAs.AddCert(x509Cert)
83         config.ClientCAs = config.RootCAs
84         return config, err
85 }
86
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) {
90         if name == "" {
91                 return x509.NewCertPool(), nil
92         }
93         pem, err := ioutil.ReadFile(name)
94         if err != nil {
95                 return nil, errors.Wrap(err)
96         }
97         pool := x509.NewCertPool()
98         ok := pool.AppendCertsFromPEM(pem)
99         if !ok {
100                 return nil, errors.Wrap(errors.New("cannot parse certs"))
101         }
102         return pool, nil
103 }