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  }