github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/cryptogen/msp/msp.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  package msp
     7  
     8  import (
     9  	"crypto/x509"
    10  	"encoding/pem"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	"github.com/hechain20/hechain/internal/cryptogen/ca"
    15  	"github.com/hechain20/hechain/internal/cryptogen/csp"
    16  	fabricmsp "github.com/hechain20/hechain/msp"
    17  	"github.com/pkg/errors"
    18  	"gopkg.in/yaml.v2"
    19  )
    20  
    21  const (
    22  	CLIENT = iota
    23  	ORDERER
    24  	PEER
    25  	ADMIN
    26  )
    27  
    28  const (
    29  	CLIENTOU  = "client"
    30  	PEEROU    = "peer"
    31  	ADMINOU   = "admin"
    32  	ORDEREROU = "orderer"
    33  )
    34  
    35  var nodeOUMap = map[int]string{
    36  	CLIENT:  CLIENTOU,
    37  	PEER:    PEEROU,
    38  	ADMIN:   ADMINOU,
    39  	ORDERER: ORDEREROU,
    40  }
    41  
    42  func GenerateLocalMSP(
    43  	baseDir,
    44  	name string,
    45  	sans []string,
    46  	signCA *ca.CA,
    47  	tlsCA *ca.CA,
    48  	nodeType int,
    49  	nodeOUs bool,
    50  ) error {
    51  	// create folder structure
    52  	mspDir := filepath.Join(baseDir, "msp")
    53  	tlsDir := filepath.Join(baseDir, "tls")
    54  
    55  	err := createFolderStructure(mspDir, true)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	err = os.MkdirAll(tlsDir, 0o755)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	/*
    66  		Create the MSP identity artifacts
    67  	*/
    68  	// get keystore path
    69  	keystore := filepath.Join(mspDir, "keystore")
    70  
    71  	// generate private key
    72  	priv, err := csp.GeneratePrivateKey(keystore)
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	// generate X509 certificate using signing CA
    78  	var ous []string
    79  	if nodeOUs {
    80  		ous = []string{nodeOUMap[nodeType]}
    81  	}
    82  	cert, err := signCA.SignCertificate(
    83  		filepath.Join(mspDir, "signcerts"),
    84  		name,
    85  		ous,
    86  		nil,
    87  		&priv.PublicKey,
    88  		x509.KeyUsageDigitalSignature,
    89  		[]x509.ExtKeyUsage{},
    90  	)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	// write artifacts to MSP folders
    96  
    97  	// the signing CA certificate goes into cacerts
    98  	err = x509Export(
    99  		filepath.Join(mspDir, "cacerts", x509Filename(signCA.Name)),
   100  		signCA.SignCert,
   101  	)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	// the TLS CA certificate goes into tlscacerts
   106  	err = x509Export(
   107  		filepath.Join(mspDir, "tlscacerts", x509Filename(tlsCA.Name)),
   108  		tlsCA.SignCert,
   109  	)
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	// generate config.yaml if required
   115  	if nodeOUs {
   116  		exportConfig(mspDir, filepath.Join("cacerts", x509Filename(signCA.Name)), true)
   117  	}
   118  
   119  	// the signing identity goes into admincerts.
   120  	// This means that the signing identity
   121  	// of this MSP is also an admin of this MSP
   122  	// NOTE: the admincerts folder is going to be
   123  	// cleared up anyway by copyAdminCert, but
   124  	// we leave a valid admin for now for the sake
   125  	// of unit tests
   126  	if !nodeOUs {
   127  		err = x509Export(filepath.Join(mspDir, "admincerts", x509Filename(name)), cert)
   128  		if err != nil {
   129  			return err
   130  		}
   131  	}
   132  
   133  	/*
   134  		Generate the TLS artifacts in the TLS folder
   135  	*/
   136  
   137  	// generate private key
   138  	tlsPrivKey, err := csp.GeneratePrivateKey(tlsDir)
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	// generate X509 certificate using TLS CA
   144  	_, err = tlsCA.SignCertificate(
   145  		filepath.Join(tlsDir),
   146  		name,
   147  		nil,
   148  		sans,
   149  		&tlsPrivKey.PublicKey,
   150  		x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
   151  		[]x509.ExtKeyUsage{
   152  			x509.ExtKeyUsageServerAuth,
   153  			x509.ExtKeyUsageClientAuth,
   154  		},
   155  	)
   156  	if err != nil {
   157  		return err
   158  	}
   159  	err = x509Export(filepath.Join(tlsDir, "ca.crt"), tlsCA.SignCert)
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	// rename the generated TLS X509 cert
   165  	tlsFilePrefix := "server"
   166  	if nodeType == CLIENT || nodeType == ADMIN {
   167  		tlsFilePrefix = "client"
   168  	}
   169  	err = os.Rename(filepath.Join(tlsDir, x509Filename(name)),
   170  		filepath.Join(tlsDir, tlsFilePrefix+".crt"))
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	err = keyExport(tlsDir, filepath.Join(tlsDir, tlsFilePrefix+".key"))
   176  	if err != nil {
   177  		return err
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func GenerateVerifyingMSP(
   184  	baseDir string,
   185  	signCA,
   186  	tlsCA *ca.CA,
   187  	nodeOUs bool,
   188  ) error {
   189  	// create folder structure and write artifacts to proper locations
   190  	err := createFolderStructure(baseDir, false)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	// the signing CA certificate goes into cacerts
   195  	err = x509Export(
   196  		filepath.Join(baseDir, "cacerts", x509Filename(signCA.Name)),
   197  		signCA.SignCert,
   198  	)
   199  	if err != nil {
   200  		return err
   201  	}
   202  	// the TLS CA certificate goes into tlscacerts
   203  	err = x509Export(
   204  		filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)),
   205  		tlsCA.SignCert,
   206  	)
   207  	if err != nil {
   208  		return err
   209  	}
   210  
   211  	// generate config.yaml if required
   212  	if nodeOUs {
   213  		exportConfig(baseDir, "cacerts/"+x509Filename(signCA.Name), true)
   214  	}
   215  
   216  	// create a throwaway cert to act as an admin cert
   217  	// NOTE: the admincerts folder is going to be
   218  	// cleared up anyway by copyAdminCert, but
   219  	// we leave a valid admin for now for the sake
   220  	// of unit tests
   221  	if nodeOUs {
   222  		return nil
   223  	}
   224  
   225  	ksDir := filepath.Join(baseDir, "keystore")
   226  	err = os.Mkdir(ksDir, 0o755)
   227  	defer os.RemoveAll(ksDir)
   228  	if err != nil {
   229  		return errors.WithMessage(err, "failed to create keystore directory")
   230  	}
   231  	priv, err := csp.GeneratePrivateKey(ksDir)
   232  	if err != nil {
   233  		return err
   234  	}
   235  	_, err = signCA.SignCertificate(
   236  		filepath.Join(baseDir, "admincerts"),
   237  		signCA.Name,
   238  		nil,
   239  		nil,
   240  		&priv.PublicKey,
   241  		x509.KeyUsageDigitalSignature,
   242  		[]x509.ExtKeyUsage{},
   243  	)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  func createFolderStructure(rootDir string, local bool) error {
   252  	var folders []string
   253  	// create admincerts, cacerts, keystore and signcerts folders
   254  	folders = []string{
   255  		filepath.Join(rootDir, "admincerts"),
   256  		filepath.Join(rootDir, "cacerts"),
   257  		filepath.Join(rootDir, "tlscacerts"),
   258  	}
   259  	if local {
   260  		folders = append(folders, filepath.Join(rootDir, "keystore"),
   261  			filepath.Join(rootDir, "signcerts"))
   262  	}
   263  
   264  	for _, folder := range folders {
   265  		err := os.MkdirAll(folder, 0o755)
   266  		if err != nil {
   267  			return err
   268  		}
   269  	}
   270  
   271  	return nil
   272  }
   273  
   274  func x509Filename(name string) string {
   275  	return name + "-cert.pem"
   276  }
   277  
   278  func x509Export(path string, cert *x509.Certificate) error {
   279  	return pemExport(path, "CERTIFICATE", cert.Raw)
   280  }
   281  
   282  func keyExport(keystore, output string) error {
   283  	return os.Rename(filepath.Join(keystore, "priv_sk"), output)
   284  }
   285  
   286  func pemExport(path, pemType string, bytes []byte) error {
   287  	// write pem out to file
   288  	file, err := os.Create(path)
   289  	if err != nil {
   290  		return err
   291  	}
   292  	defer file.Close()
   293  
   294  	return pem.Encode(file, &pem.Block{Type: pemType, Bytes: bytes})
   295  }
   296  
   297  func exportConfig(mspDir, caFile string, enable bool) error {
   298  	config := &fabricmsp.Configuration{
   299  		NodeOUs: &fabricmsp.NodeOUs{
   300  			Enable: enable,
   301  			ClientOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   302  				Certificate:                  caFile,
   303  				OrganizationalUnitIdentifier: CLIENTOU,
   304  			},
   305  			PeerOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   306  				Certificate:                  caFile,
   307  				OrganizationalUnitIdentifier: PEEROU,
   308  			},
   309  			AdminOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   310  				Certificate:                  caFile,
   311  				OrganizationalUnitIdentifier: ADMINOU,
   312  			},
   313  			OrdererOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   314  				Certificate:                  caFile,
   315  				OrganizationalUnitIdentifier: ORDEREROU,
   316  			},
   317  		},
   318  	}
   319  
   320  	configBytes, err := yaml.Marshal(config)
   321  	if err != nil {
   322  		return err
   323  	}
   324  
   325  	file, err := os.Create(filepath.Join(mspDir, "config.yaml"))
   326  	if err != nil {
   327  		return err
   328  	}
   329  
   330  	defer file.Close()
   331  	_, err = file.WriteString(string(configBytes))
   332  
   333  	return err
   334  }