github.com/bestbeforetoday/fabric-ca@v2.0.0-alpha+incompatible/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/cloudflare/cfssl/log"
    26  	"github.com/hyperledger/fabric-ca/util"
    27  	"github.com/hyperledger/fabric/bccsp"
    28  	"github.com/hyperledger/fabric/bccsp/factory"
    29  	"github.com/pkg/errors"
    30  )
    31  
    32  // DefaultCipherSuites is a set of strong TLS cipher suites
    33  var DefaultCipherSuites = []uint16{
    34  	tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    35  	tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
    36  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    37  	tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
    38  	tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
    39  	tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
    40  }
    41  
    42  // ServerTLSConfig defines key material for a TLS server
    43  type ServerTLSConfig struct {
    44  	Enabled    bool   `help:"Enable TLS on the listening port"`
    45  	CertFile   string `def:"tls-cert.pem" help:"PEM-encoded TLS certificate file for server's listening port"`
    46  	KeyFile    string `help:"PEM-encoded TLS key for server's listening port"`
    47  	ClientAuth ClientAuth
    48  }
    49  
    50  // ClientAuth defines the key material needed to verify client certificates
    51  type ClientAuth struct {
    52  	Type      string   `def:"noclientcert" help:"Policy the server will follow for TLS Client Authentication."`
    53  	CertFiles []string `help:"A list of comma-separated PEM-encoded trusted certificate files (e.g. root1.pem,root2.pem)"`
    54  }
    55  
    56  // ClientTLSConfig defines the key material for a TLS client
    57  type ClientTLSConfig struct {
    58  	Enabled   bool     `skip:"true"`
    59  	CertFiles []string `help:"A list of comma-separated PEM-encoded trusted certificate files (e.g. root1.pem,root2.pem)"`
    60  	Client    KeyCertFiles
    61  }
    62  
    63  // KeyCertFiles defines the files need for client on TLS
    64  type KeyCertFiles struct {
    65  	KeyFile  string `help:"PEM-encoded key file when mutual authentication is enabled"`
    66  	CertFile string `help:"PEM-encoded certificate file when mutual authenticate is enabled"`
    67  }
    68  
    69  // GetClientTLSConfig creates a tls.Config object from certs and roots
    70  func GetClientTLSConfig(cfg *ClientTLSConfig, csp bccsp.BCCSP) (*tls.Config, error) {
    71  	var certs []tls.Certificate
    72  
    73  	if csp == nil {
    74  		csp = factory.GetDefault()
    75  	}
    76  
    77  	log.Debugf("CA Files: %+v\n", cfg.CertFiles)
    78  	log.Debugf("Client Cert File: %s\n", cfg.Client.CertFile)
    79  	log.Debugf("Client Key File: %s\n", cfg.Client.KeyFile)
    80  
    81  	if cfg.Client.CertFile != "" {
    82  		err := checkCertDates(cfg.Client.CertFile)
    83  		if err != nil {
    84  			return nil, err
    85  		}
    86  
    87  		clientCert, err := util.LoadX509KeyPair(cfg.Client.CertFile, cfg.Client.KeyFile, csp)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  
    92  		certs = append(certs, *clientCert)
    93  	} else {
    94  		log.Debug("Client TLS certificate and/or key file not provided")
    95  	}
    96  	rootCAPool := x509.NewCertPool()
    97  	if len(cfg.CertFiles) == 0 {
    98  		return nil, errors.New("No trusted root certificates for TLS were provided")
    99  	}
   100  
   101  	for _, cacert := range cfg.CertFiles {
   102  		caCert, err := ioutil.ReadFile(cacert)
   103  		if err != nil {
   104  			return nil, errors.Wrapf(err, "Failed to read '%s'", cacert)
   105  		}
   106  		ok := rootCAPool.AppendCertsFromPEM(caCert)
   107  		if !ok {
   108  			return nil, errors.Errorf("Failed to process certificate from file %s", cacert)
   109  		}
   110  	}
   111  
   112  	config := &tls.Config{
   113  		Certificates: certs,
   114  		RootCAs:      rootCAPool,
   115  	}
   116  
   117  	return config, nil
   118  }
   119  
   120  // AbsTLSClient makes TLS client files absolute
   121  func AbsTLSClient(cfg *ClientTLSConfig, configDir string) error {
   122  	var err error
   123  
   124  	for i := 0; i < len(cfg.CertFiles); i++ {
   125  		cfg.CertFiles[i], err = util.MakeFileAbs(cfg.CertFiles[i], configDir)
   126  		if err != nil {
   127  			return err
   128  		}
   129  
   130  	}
   131  
   132  	cfg.Client.CertFile, err = util.MakeFileAbs(cfg.Client.CertFile, configDir)
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	cfg.Client.KeyFile, err = util.MakeFileAbs(cfg.Client.KeyFile, configDir)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  // AbsTLSServer makes TLS client files absolute
   146  func AbsTLSServer(cfg *ServerTLSConfig, configDir string) error {
   147  	var err error
   148  
   149  	for i := 0; i < len(cfg.ClientAuth.CertFiles); i++ {
   150  		cfg.ClientAuth.CertFiles[i], err = util.MakeFileAbs(cfg.ClientAuth.CertFiles[i], configDir)
   151  		if err != nil {
   152  			return err
   153  		}
   154  
   155  	}
   156  
   157  	cfg.CertFile, err = util.MakeFileAbs(cfg.CertFile, configDir)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	cfg.KeyFile, err = util.MakeFileAbs(cfg.KeyFile, configDir)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	return nil
   168  }
   169  
   170  func checkCertDates(certFile string) error {
   171  	log.Debug("Check client TLS certificate for valid dates")
   172  	certPEM, err := ioutil.ReadFile(certFile)
   173  	if err != nil {
   174  		return errors.Wrapf(err, "Failed to read file '%s'", certFile)
   175  	}
   176  
   177  	cert, err := util.GetX509CertificateFromPEM(certPEM)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	notAfter := cert.NotAfter
   183  	currentTime := time.Now().UTC()
   184  
   185  	if currentTime.After(notAfter) {
   186  		return errors.New("Certificate provided has expired")
   187  	}
   188  
   189  	notBefore := cert.NotBefore
   190  	if currentTime.Before(notBefore) {
   191  		return errors.New("Certificate provided not valid until later date")
   192  	}
   193  
   194  	return nil
   195  }