github.com/kaituanwang/hyperledger@v2.0.1+incompatible/internal/cryptogen/msp/msp.go (about)

     1  /*
     2  Copyright IBM Corp. 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/hyperledger/fabric/internal/cryptogen/ca"
    15  	"github.com/hyperledger/fabric/internal/cryptogen/csp"
    16  	fabricmsp "github.com/hyperledger/fabric/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  
    52  	// create folder structure
    53  	mspDir := filepath.Join(baseDir, "msp")
    54  	tlsDir := filepath.Join(baseDir, "tls")
    55  
    56  	err := createFolderStructure(mspDir, true)
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	err = os.MkdirAll(tlsDir, 0755)
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	/*
    67  		Create the MSP identity artifacts
    68  	*/
    69  	// get keystore path
    70  	keystore := filepath.Join(mspDir, "keystore")
    71  
    72  	// generate private key
    73  	priv, err := csp.GeneratePrivateKey(keystore)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	// generate X509 certificate using signing CA
    79  	var ous []string
    80  	if nodeOUs {
    81  		ous = []string{nodeOUMap[nodeType]}
    82  	}
    83  	cert, err := signCA.SignCertificate(
    84  		filepath.Join(mspDir, "signcerts"),
    85  		name,
    86  		ous,
    87  		nil,
    88  		&priv.PublicKey,
    89  		x509.KeyUsageDigitalSignature,
    90  		[]x509.ExtKeyUsage{},
    91  	)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	// write artifacts to MSP folders
    97  
    98  	// the signing CA certificate goes into cacerts
    99  	err = x509Export(
   100  		filepath.Join(mspDir, "cacerts", x509Filename(signCA.Name)),
   101  		signCA.SignCert,
   102  	)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	// the TLS CA certificate goes into tlscacerts
   107  	err = x509Export(
   108  		filepath.Join(mspDir, "tlscacerts", x509Filename(tlsCA.Name)),
   109  		tlsCA.SignCert,
   110  	)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	// generate config.yaml if required
   116  	if nodeOUs {
   117  
   118  		exportConfig(mspDir, filepath.Join("cacerts", x509Filename(signCA.Name)), true)
   119  	}
   120  
   121  	// the signing identity goes into admincerts.
   122  	// This means that the signing identity
   123  	// of this MSP is also an admin of this MSP
   124  	// NOTE: the admincerts folder is going to be
   125  	// cleared up anyway by copyAdminCert, but
   126  	// we leave a valid admin for now for the sake
   127  	// of unit tests
   128  	if !nodeOUs {
   129  		err = x509Export(filepath.Join(mspDir, "admincerts", x509Filename(name)), cert)
   130  		if err != nil {
   131  			return err
   132  		}
   133  	}
   134  
   135  	/*
   136  		Generate the TLS artifacts in the TLS folder
   137  	*/
   138  
   139  	// generate private key
   140  	tlsPrivKey, err := csp.GeneratePrivateKey(tlsDir)
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	// generate X509 certificate using TLS CA
   146  	_, err = tlsCA.SignCertificate(
   147  		filepath.Join(tlsDir),
   148  		name,
   149  		nil,
   150  		sans,
   151  		&tlsPrivKey.PublicKey,
   152  		x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
   153  		[]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth,
   154  			x509.ExtKeyUsageClientAuth},
   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  
   190  	// create folder structure and write artifacts to proper locations
   191  	err := createFolderStructure(baseDir, false)
   192  	if err != nil {
   193  		return err
   194  	}
   195  	// the signing CA certificate goes into cacerts
   196  	err = x509Export(
   197  		filepath.Join(baseDir, "cacerts", x509Filename(signCA.Name)),
   198  		signCA.SignCert,
   199  	)
   200  	if err != nil {
   201  		return err
   202  	}
   203  	// the TLS CA certificate goes into tlscacerts
   204  	err = x509Export(
   205  		filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)),
   206  		tlsCA.SignCert,
   207  	)
   208  	if err != nil {
   209  		return err
   210  	}
   211  
   212  	// generate config.yaml if required
   213  	if nodeOUs {
   214  		exportConfig(baseDir, "cacerts/"+x509Filename(signCA.Name), true)
   215  	}
   216  
   217  	// create a throwaway cert to act as an admin cert
   218  	// NOTE: the admincerts folder is going to be
   219  	// cleared up anyway by copyAdminCert, but
   220  	// we leave a valid admin for now for the sake
   221  	// of unit tests
   222  	if nodeOUs {
   223  		return nil
   224  	}
   225  
   226  	ksDir := filepath.Join(baseDir, "keystore")
   227  	err = os.Mkdir(ksDir, 0755)
   228  	defer os.RemoveAll(ksDir)
   229  	if err != nil {
   230  		return errors.WithMessage(err, "failed to create keystore directory")
   231  	}
   232  	priv, err := csp.GeneratePrivateKey(ksDir)
   233  	if err != nil {
   234  		return err
   235  	}
   236  	_, err = signCA.SignCertificate(
   237  		filepath.Join(baseDir, "admincerts"),
   238  		signCA.Name,
   239  		nil,
   240  		nil,
   241  		&priv.PublicKey,
   242  		x509.KeyUsageDigitalSignature,
   243  		[]x509.ExtKeyUsage{},
   244  	)
   245  	if err != nil {
   246  		return err
   247  	}
   248  
   249  	return nil
   250  }
   251  
   252  func createFolderStructure(rootDir string, local bool) error {
   253  
   254  	var folders []string
   255  	// create admincerts, cacerts, keystore and signcerts folders
   256  	folders = []string{
   257  		filepath.Join(rootDir, "admincerts"),
   258  		filepath.Join(rootDir, "cacerts"),
   259  		filepath.Join(rootDir, "tlscacerts"),
   260  	}
   261  	if local {
   262  		folders = append(folders, filepath.Join(rootDir, "keystore"),
   263  			filepath.Join(rootDir, "signcerts"))
   264  	}
   265  
   266  	for _, folder := range folders {
   267  		err := os.MkdirAll(folder, 0755)
   268  		if err != nil {
   269  			return err
   270  		}
   271  	}
   272  
   273  	return nil
   274  }
   275  
   276  func x509Filename(name string) string {
   277  	return name + "-cert.pem"
   278  }
   279  
   280  func x509Export(path string, cert *x509.Certificate) error {
   281  	return pemExport(path, "CERTIFICATE", cert.Raw)
   282  }
   283  
   284  func keyExport(keystore, output string) error {
   285  	return os.Rename(filepath.Join(keystore, "priv_sk"), output)
   286  }
   287  
   288  func pemExport(path, pemType string, bytes []byte) error {
   289  	//write pem out to file
   290  	file, err := os.Create(path)
   291  	if err != nil {
   292  		return err
   293  	}
   294  	defer file.Close()
   295  
   296  	return pem.Encode(file, &pem.Block{Type: pemType, Bytes: bytes})
   297  }
   298  
   299  func exportConfig(mspDir, caFile string, enable bool) error {
   300  	var config = &fabricmsp.Configuration{
   301  		NodeOUs: &fabricmsp.NodeOUs{
   302  			Enable: enable,
   303  			ClientOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   304  				Certificate:                  caFile,
   305  				OrganizationalUnitIdentifier: CLIENTOU,
   306  			},
   307  			PeerOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   308  				Certificate:                  caFile,
   309  				OrganizationalUnitIdentifier: PEEROU,
   310  			},
   311  			AdminOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   312  				Certificate:                  caFile,
   313  				OrganizationalUnitIdentifier: ADMINOU,
   314  			},
   315  			OrdererOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
   316  				Certificate:                  caFile,
   317  				OrganizationalUnitIdentifier: ORDEREROU,
   318  			},
   319  		},
   320  	}
   321  
   322  	configBytes, err := yaml.Marshal(config)
   323  	if err != nil {
   324  		return err
   325  	}
   326  
   327  	file, err := os.Create(filepath.Join(mspDir, "config.yaml"))
   328  	if err != nil {
   329  		return err
   330  	}
   331  
   332  	defer file.Close()
   333  	_, err = file.WriteString(string(configBytes))
   334  
   335  	return err
   336  }