335 lines
7.0 KiB
Go
335 lines
7.0 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
package msp
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/hyperledger/fabric/internal/cryptogen/ca"
|
|
"github.com/hyperledger/fabric/internal/cryptogen/csp"
|
|
fabricmsp "github.com/hyperledger/fabric/msp"
|
|
"github.com/pkg/errors"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
const (
|
|
CLIENT = iota
|
|
ORDERER
|
|
PEER
|
|
ADMIN
|
|
)
|
|
|
|
const (
|
|
CLIENTOU = "client"
|
|
PEEROU = "peer"
|
|
ADMINOU = "admin"
|
|
ORDEREROU = "orderer"
|
|
)
|
|
|
|
var nodeOUMap = map[int]string{
|
|
CLIENT: CLIENTOU,
|
|
PEER: PEEROU,
|
|
ADMIN: ADMINOU,
|
|
ORDERER: ORDEREROU,
|
|
}
|
|
|
|
func GenerateLocalMSP(
|
|
baseDir,
|
|
name string,
|
|
sans []string,
|
|
signCA *ca.CA,
|
|
tlsCA *ca.CA,
|
|
nodeType int,
|
|
nodeOUs bool,
|
|
) error {
|
|
// create folder structure
|
|
mspDir := filepath.Join(baseDir, "msp")
|
|
tlsDir := filepath.Join(baseDir, "tls")
|
|
|
|
err := createFolderStructure(mspDir, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = os.MkdirAll(tlsDir, 0o755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
/*
|
|
Create the MSP identity artifacts
|
|
*/
|
|
// get keystore path
|
|
keystore := filepath.Join(mspDir, "keystore")
|
|
|
|
// generate private key
|
|
priv, err := csp.GeneratePrivateKey(keystore)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// generate X509 certificate using signing CA
|
|
var ous []string
|
|
if nodeOUs {
|
|
ous = []string{nodeOUMap[nodeType]}
|
|
}
|
|
cert, err := signCA.SignCertificate(
|
|
filepath.Join(mspDir, "signcerts"),
|
|
name,
|
|
ous,
|
|
nil,
|
|
&priv.PublicKey,
|
|
x509.KeyUsageDigitalSignature,
|
|
[]x509.ExtKeyUsage{},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// write artifacts to MSP folders
|
|
|
|
// the signing CA certificate goes into cacerts
|
|
err = x509Export(
|
|
filepath.Join(mspDir, "cacerts", x509Filename(signCA.Name)),
|
|
signCA.SignCert,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// the TLS CA certificate goes into tlscacerts
|
|
err = x509Export(
|
|
filepath.Join(mspDir, "tlscacerts", x509Filename(tlsCA.Name)),
|
|
tlsCA.SignCert,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// generate config.yaml if required
|
|
if nodeOUs {
|
|
exportConfig(mspDir, filepath.Join("cacerts", x509Filename(signCA.Name)), true)
|
|
}
|
|
|
|
// the signing identity goes into admincerts.
|
|
// This means that the signing identity
|
|
// of this MSP is also an admin of this MSP
|
|
// NOTE: the admincerts folder is going to be
|
|
// cleared up anyway by copyAdminCert, but
|
|
// we leave a valid admin for now for the sake
|
|
// of unit tests
|
|
if !nodeOUs {
|
|
err = x509Export(filepath.Join(mspDir, "admincerts", x509Filename(name)), cert)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
/*
|
|
Generate the TLS artifacts in the TLS folder
|
|
*/
|
|
|
|
// generate private key
|
|
tlsPrivKey, err := csp.GeneratePrivateKey(tlsDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// generate X509 certificate using TLS CA
|
|
_, err = tlsCA.SignCertificate(
|
|
filepath.Join(tlsDir),
|
|
name,
|
|
nil,
|
|
sans,
|
|
&tlsPrivKey.PublicKey,
|
|
x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment,
|
|
[]x509.ExtKeyUsage{
|
|
x509.ExtKeyUsageServerAuth,
|
|
x509.ExtKeyUsageClientAuth,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = x509Export(filepath.Join(tlsDir, "ca.crt"), tlsCA.SignCert)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// rename the generated TLS X509 cert
|
|
tlsFilePrefix := "server"
|
|
if nodeType == CLIENT || nodeType == ADMIN {
|
|
tlsFilePrefix = "client"
|
|
}
|
|
err = os.Rename(filepath.Join(tlsDir, x509Filename(name)),
|
|
filepath.Join(tlsDir, tlsFilePrefix+".crt"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = keyExport(tlsDir, filepath.Join(tlsDir, tlsFilePrefix+".key"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func GenerateVerifyingMSP(
|
|
baseDir string,
|
|
signCA,
|
|
tlsCA *ca.CA,
|
|
nodeOUs bool,
|
|
) error {
|
|
// create folder structure and write artifacts to proper locations
|
|
err := createFolderStructure(baseDir, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// the signing CA certificate goes into cacerts
|
|
err = x509Export(
|
|
filepath.Join(baseDir, "cacerts", x509Filename(signCA.Name)),
|
|
signCA.SignCert,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// the TLS CA certificate goes into tlscacerts
|
|
err = x509Export(
|
|
filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)),
|
|
tlsCA.SignCert,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// generate config.yaml if required
|
|
if nodeOUs {
|
|
exportConfig(baseDir, "cacerts/"+x509Filename(signCA.Name), true)
|
|
}
|
|
|
|
// create a throwaway cert to act as an admin cert
|
|
// NOTE: the admincerts folder is going to be
|
|
// cleared up anyway by copyAdminCert, but
|
|
// we leave a valid admin for now for the sake
|
|
// of unit tests
|
|
if nodeOUs {
|
|
return nil
|
|
}
|
|
|
|
ksDir := filepath.Join(baseDir, "keystore")
|
|
err = os.Mkdir(ksDir, 0o755)
|
|
defer os.RemoveAll(ksDir)
|
|
if err != nil {
|
|
return errors.WithMessage(err, "failed to create keystore directory")
|
|
}
|
|
priv, err := csp.GeneratePrivateKey(ksDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = signCA.SignCertificate(
|
|
filepath.Join(baseDir, "admincerts"),
|
|
signCA.Name,
|
|
nil,
|
|
nil,
|
|
&priv.PublicKey,
|
|
x509.KeyUsageDigitalSignature,
|
|
[]x509.ExtKeyUsage{},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func createFolderStructure(rootDir string, local bool) error {
|
|
var folders []string
|
|
// create admincerts, cacerts, keystore and signcerts folders
|
|
folders = []string{
|
|
filepath.Join(rootDir, "admincerts"),
|
|
filepath.Join(rootDir, "cacerts"),
|
|
filepath.Join(rootDir, "tlscacerts"),
|
|
}
|
|
if local {
|
|
folders = append(folders, filepath.Join(rootDir, "keystore"),
|
|
filepath.Join(rootDir, "signcerts"))
|
|
}
|
|
|
|
for _, folder := range folders {
|
|
err := os.MkdirAll(folder, 0o755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func x509Filename(name string) string {
|
|
return name + "-cert.pem"
|
|
}
|
|
|
|
func x509Export(path string, cert *x509.Certificate) error {
|
|
return pemExport(path, "CERTIFICATE", cert.Raw)
|
|
}
|
|
|
|
func keyExport(keystore, output string) error {
|
|
return os.Rename(filepath.Join(keystore, "priv_sk"), output)
|
|
}
|
|
|
|
func pemExport(path, pemType string, bytes []byte) error {
|
|
// write pem out to file
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
return pem.Encode(file, &pem.Block{Type: pemType, Bytes: bytes})
|
|
}
|
|
|
|
func exportConfig(mspDir, caFile string, enable bool) error {
|
|
config := &fabricmsp.Configuration{
|
|
NodeOUs: &fabricmsp.NodeOUs{
|
|
Enable: enable,
|
|
ClientOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
|
|
Certificate: caFile,
|
|
OrganizationalUnitIdentifier: CLIENTOU,
|
|
},
|
|
PeerOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
|
|
Certificate: caFile,
|
|
OrganizationalUnitIdentifier: PEEROU,
|
|
},
|
|
AdminOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
|
|
Certificate: caFile,
|
|
OrganizationalUnitIdentifier: ADMINOU,
|
|
},
|
|
OrdererOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{
|
|
Certificate: caFile,
|
|
OrganizationalUnitIdentifier: ORDEREROU,
|
|
},
|
|
},
|
|
}
|
|
|
|
configBytes, err := yaml.Marshal(config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
file, err := os.Create(filepath.Join(mspDir, "config.yaml"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer file.Close()
|
|
_, err = file.WriteString(string(configBytes))
|
|
|
|
return err
|
|
}
|