github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/ca/tls/tls.go (about)

     1  /*
     2   * Copyright contributors to the Hyperledger Fabric Operator project
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at:
     9   *
    10   * 	  http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  package tls
    20  
    21  import (
    22  	"crypto/ecdsa"
    23  	"crypto/rand"
    24  	"crypto/x509"
    25  	"crypto/x509/pkix"
    26  	"encoding/pem"
    27  	"math/big"
    28  	"net"
    29  	"os"
    30  	"path/filepath"
    31  	"time"
    32  
    33  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    34  	"github.com/cloudflare/cfssl/csr"
    35  	"github.com/hyperledger/fabric-ca/api"
    36  	cautil "github.com/hyperledger/fabric-ca/util"
    37  	"github.com/hyperledger/fabric/bccsp/factory"
    38  )
    39  
    40  type TLS struct {
    41  	CAHomeDir string
    42  	CSP       *factory.FactoryOpts
    43  }
    44  
    45  func (t *TLS) GenerateSelfSignedTLSCrypto(csr *api.CSRInfo) ([]byte, error) {
    46  	err := os.RemoveAll(filepath.Join(t.CAHomeDir, "tls"))
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	csp, err := cautil.InitBCCSP(&t.CSP, "msp", filepath.Join(t.CAHomeDir, "tls"))
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	cr := NewCertificateRequest(csr)
    57  	privKey, signer, err := cautil.BCCSPKeyRequestGenerate(cr, csp)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	notBefore := time.Now()
    63  	notBefore.Add(-5 * time.Minute)
    64  	notAfter := notBefore.Add(time.Hour * 24 * 365) // Valid for one year
    65  
    66  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    67  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	subject := pkix.Name{
    73  		CommonName:   csr.CN,
    74  		SerialNumber: csr.SerialNumber,
    75  	}
    76  	if len(csr.Names) != 0 {
    77  		for _, name := range csr.Names {
    78  			subject.Country = append(subject.Country, name.C)
    79  			subject.Province = append(subject.Province, name.ST)
    80  			subject.Locality = append(subject.Locality, name.L)
    81  			subject.Organization = append(subject.Organization, name.O)
    82  			subject.OrganizationalUnit = append(subject.OrganizationalUnit, name.OU)
    83  		}
    84  	}
    85  
    86  	template := x509.Certificate{
    87  		SerialNumber: serialNumber,
    88  		Subject:      subject,
    89  		NotBefore:    notBefore,
    90  		NotAfter:     notAfter,
    91  
    92  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    93  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    94  		BasicConstraintsValid: true,
    95  	}
    96  
    97  	for _, h := range csr.Hosts {
    98  		ip := net.ParseIP(h)
    99  		if ip != nil {
   100  			template.IPAddresses = append(template.IPAddresses, ip)
   101  		} else {
   102  			template.DNSNames = append(template.DNSNames, h)
   103  		}
   104  	}
   105  
   106  	pubKey, err := privKey.PublicKey()
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	pubKeyBytes, err := pubKey.Bytes()
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	pub, err := x509.ParsePKIXPublicKey(pubKeyBytes)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	ecdsaPubKey := pub.(*ecdsa.PublicKey)
   119  
   120  	certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, ecdsaPubKey, signer)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	return certBytes, nil
   126  }
   127  
   128  func (t *TLS) WriteCryptoToFile(cert []byte, certName string) error {
   129  	certPath := filepath.Join(t.CAHomeDir, "tls", certName)
   130  	err := util.EnsureDir(filepath.Dir(certPath))
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	certOut, err := os.Create(filepath.Clean(certPath))
   136  	if err != nil {
   137  		return err
   138  	}
   139  	err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: cert})
   140  	if err != nil {
   141  		return err
   142  	}
   143  	err = certOut.Close()
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	return nil
   149  }
   150  
   151  func NewCertificateRequest(req *api.CSRInfo) *csr.CertificateRequest {
   152  	cr := csr.CertificateRequest{}
   153  	if req != nil && req.Names != nil {
   154  		cr.Names = req.Names
   155  	}
   156  	if req != nil && req.Hosts != nil {
   157  		cr.Hosts = req.Hosts
   158  	} else {
   159  		// Default requested hosts are local hostname
   160  		hostname, err := os.Hostname()
   161  		if err == nil && hostname != "" {
   162  			cr.Hosts = make([]string, 1)
   163  			cr.Hosts[0] = hostname
   164  		}
   165  	}
   166  	if req != nil && req.KeyRequest != nil {
   167  		cr.KeyRequest = newCfsslKeyRequest(req.KeyRequest)
   168  	}
   169  	if req != nil {
   170  		cr.CA = req.CA
   171  		cr.SerialNumber = req.SerialNumber
   172  	}
   173  	return &cr
   174  }
   175  
   176  func newCfsslKeyRequest(bkr *api.KeyRequest) *csr.KeyRequest {
   177  	return &csr.KeyRequest{A: bkr.Algo, S: bkr.Size}
   178  }