github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/tls/tls.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tls 18 19 import ( 20 "crypto/tls" 21 "crypto/x509" 22 "io/ioutil" 23 "time" 24 25 "github.com/pkg/errors" 26 27 "github.com/cloudflare/cfssl/log" 28 "github.com/hyperledger/fabric-ca/util" 29 "github.com/hyperledger/fabric/bccsp" 30 "github.com/hyperledger/fabric/bccsp/factory" 31 ) 32 33 // ServerTLSConfig defines key material for a TLS server 34 type ServerTLSConfig struct { 35 Enabled bool `help:"Enable TLS on the listening port"` 36 CertFile string `def:"tls-cert.pem" help:"PEM-encoded TLS certificate file for server's listening port"` 37 KeyFile string `help:"PEM-encoded TLS key for server's listening port"` 38 ClientAuth ClientAuth 39 } 40 41 // ClientAuth defines the key material needed to verify client certificates 42 type ClientAuth struct { 43 Type string `def:"noclientcert" help:"Policy the server will follow for TLS Client Authentication."` 44 CertFiles []string `help:"A list of comma-separated PEM-encoded trusted certificate files (e.g. root1.pem,root2.pem)"` 45 } 46 47 // ClientTLSConfig defines the key material for a TLS client 48 type ClientTLSConfig struct { 49 Enabled bool `skip:"true"` 50 CertFiles []string `help:"A list of comma-separated PEM-encoded trusted certificate files (e.g. root1.pem,root2.pem)"` 51 Client KeyCertFiles 52 } 53 54 // KeyCertFiles defines the files need for client on TLS 55 type KeyCertFiles struct { 56 KeyFile string `help:"PEM-encoded key file when mutual authentication is enabled"` 57 CertFile string `help:"PEM-encoded certificate file when mutual authenticate is enabled"` 58 } 59 60 // GetClientTLSConfig creates a tls.Config object from certs and roots 61 func GetClientTLSConfig(cfg *ClientTLSConfig, csp bccsp.BCCSP) (*tls.Config, error) { 62 var certs []tls.Certificate 63 64 if csp == nil { 65 csp = factory.GetDefault() 66 } 67 68 log.Debugf("CA Files: %+v\n", cfg.CertFiles) 69 log.Debugf("Client Cert File: %s\n", cfg.Client.CertFile) 70 log.Debugf("Client Key File: %s\n", cfg.Client.KeyFile) 71 72 if cfg.Client.CertFile != "" { 73 err := checkCertDates(cfg.Client.CertFile) 74 if err != nil { 75 return nil, err 76 } 77 78 clientCert, err := util.LoadX509KeyPair(cfg.Client.CertFile, cfg.Client.KeyFile, csp) 79 if err != nil { 80 return nil, err 81 } 82 83 certs = append(certs, *clientCert) 84 } else { 85 log.Debug("Client TLS certificate and/or key file not provided") 86 } 87 rootCAPool := x509.NewCertPool() 88 if len(cfg.CertFiles) == 0 { 89 return nil, errors.New("No TLS certificate files were provided") 90 } 91 92 for _, cacert := range cfg.CertFiles { 93 caCert, err := ioutil.ReadFile(cacert) 94 if err != nil { 95 return nil, errors.Wrapf(err, "Failed to read '%s'", cacert) 96 } 97 ok := rootCAPool.AppendCertsFromPEM(caCert) 98 if !ok { 99 return nil, errors.Errorf("Failed to process certificate from file %s", cacert) 100 } 101 } 102 103 config := &tls.Config{ 104 Certificates: certs, 105 RootCAs: rootCAPool, 106 } 107 108 return config, nil 109 } 110 111 // AbsTLSClient makes TLS client files absolute 112 func AbsTLSClient(cfg *ClientTLSConfig, configDir string) error { 113 var err error 114 115 for i := 0; i < len(cfg.CertFiles); i++ { 116 cfg.CertFiles[i], err = util.MakeFileAbs(cfg.CertFiles[i], configDir) 117 if err != nil { 118 return err 119 } 120 121 } 122 123 cfg.Client.CertFile, err = util.MakeFileAbs(cfg.Client.CertFile, configDir) 124 if err != nil { 125 return err 126 } 127 128 cfg.Client.KeyFile, err = util.MakeFileAbs(cfg.Client.KeyFile, configDir) 129 if err != nil { 130 return err 131 } 132 133 return nil 134 } 135 136 // AbsTLSServer makes TLS client files absolute 137 func AbsTLSServer(cfg *ServerTLSConfig, configDir string) error { 138 var err error 139 140 for i := 0; i < len(cfg.ClientAuth.CertFiles); i++ { 141 cfg.ClientAuth.CertFiles[i], err = util.MakeFileAbs(cfg.ClientAuth.CertFiles[i], configDir) 142 if err != nil { 143 return err 144 } 145 146 } 147 148 cfg.CertFile, err = util.MakeFileAbs(cfg.CertFile, configDir) 149 if err != nil { 150 return err 151 } 152 153 cfg.KeyFile, err = util.MakeFileAbs(cfg.KeyFile, configDir) 154 if err != nil { 155 return err 156 } 157 158 return nil 159 } 160 161 func checkCertDates(certFile string) error { 162 log.Debug("Check client TLS certificate for valid dates") 163 certPEM, err := ioutil.ReadFile(certFile) 164 if err != nil { 165 return errors.Wrapf(err, "Failed to read file '%s'", certFile) 166 } 167 168 cert, err := util.GetX509CertificateFromPEM(certPEM) 169 if err != nil { 170 return err 171 } 172 173 notAfter := cert.NotAfter 174 currentTime := time.Now().UTC() 175 176 if currentTime.After(notAfter) { 177 return errors.New("Certificate provided has expired") 178 } 179 180 notBefore := cert.NotBefore 181 if currentTime.Before(notBefore) { 182 return errors.New("Certificate provided not valid until later date") 183 } 184 185 return nil 186 }