From be91cccdf68e72365c80b650a267f8eab3ea1e63 Mon Sep 17 00:00:00 2001 From: Gari Singh Date: Mon, 27 Feb 2017 16:39:40 -0500 Subject: [PATCH] [FAB-2545] Add tool to create various crypto configs https://jira.hyperledger.org/browse/FAB-2545 In order to get a test (or even real) system running, there is a lot of cryptographic material required: - root certificates for CAs (e.g. fabric-ca) - MSPs for organizations running peers - Local MSPs for peers - MSPs for ordererer organizations - Local MSPs for ordering nodes This CR adds a tool named "cryptogen" which will create these artifacts for you. It allows you to specify the number of peer organizations, the number of peers per organization and the number of ordering nodes (shims). It currently only creates a single orderer organization. To run, "./cryptogen" and it will display the command line options Change-Id: I15f135dc2893f7492566eb8ac5d02b2f4963ccd3 Signed-off-by: Gari Singh --- common/tools/cryptogen/ca/ca_test.go | 93 ++++++++++++ common/tools/cryptogen/ca/generator.go | 181 ++++++++++++++++++++++++ common/tools/cryptogen/csp/csp.go | 79 +++++++++++ common/tools/cryptogen/csp/csp_test.go | 67 +++++++++ common/tools/cryptogen/main.go | 152 ++++++++++++++++++++ common/tools/cryptogen/msp/generator.go | 127 +++++++++++++++++ common/tools/cryptogen/msp/msp_test.go | 109 ++++++++++++++ 7 files changed, 808 insertions(+) create mode 100644 common/tools/cryptogen/ca/ca_test.go create mode 100644 common/tools/cryptogen/ca/generator.go create mode 100644 common/tools/cryptogen/csp/csp.go create mode 100644 common/tools/cryptogen/csp/csp_test.go create mode 100644 common/tools/cryptogen/main.go create mode 100644 common/tools/cryptogen/msp/generator.go create mode 100644 common/tools/cryptogen/msp/msp_test.go diff --git a/common/tools/cryptogen/ca/ca_test.go b/common/tools/cryptogen/ca/ca_test.go new file mode 100644 index 00000000000..1f3f437cb92 --- /dev/null +++ b/common/tools/cryptogen/ca/ca_test.go @@ -0,0 +1,93 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package ca_test + +import ( + "crypto/x509" + "os" + "path/filepath" + "testing" + + "github.com/hyperledger/fabric/common/tools/cryptogen/ca" + "github.com/hyperledger/fabric/common/tools/cryptogen/csp" + "github.com/stretchr/testify/assert" +) + +const ( + testCAName = "root0" + testCA2Name = "root1" + testName = "cert0" +) + +var testDir = filepath.Join(os.TempDir(), "ca-test") + +func TestNewCA(t *testing.T) { + + caDir := filepath.Join(testDir, "ca") + rootCA, err := ca.NewCA(caDir, testCAName) + assert.NoError(t, err, "Error generating CA") + assert.NotNil(t, rootCA, "Failed to return CA") + assert.NotNil(t, rootCA.Signer, + "rootCA.Signer should not be empty") + assert.IsType(t, &x509.Certificate{}, rootCA.SignCert, + "rootCA.SignCert should be type x509.Certificate") + + // check to make sure the root public key was stored + pemFile := filepath.Join(caDir, testCAName+"-cert.pem") + assert.Equal(t, true, checkForFile(pemFile), + "Expected to find file "+pemFile) + cleanup(testDir) + +} + +func TestGenerateSignedCertificate(t *testing.T) { + + caDir := filepath.Join(testDir, "ca") + certDir := filepath.Join(testDir, "certs") + // generate private key + priv, _, err := csp.GeneratePrivateKey(certDir) + assert.NoError(t, err, "Failed to generate signed certificate") + + // get EC public key + ecPubKey, err := csp.GetECPublicKey(priv) + assert.NoError(t, err, "Failed to generate signed certificate") + assert.NotNil(t, ecPubKey, "Failed to generate signed certificate") + + // create our CA + rootCA, err := ca.NewCA(caDir, testCA2Name) + assert.NoError(t, err, "Error generating CA") + + err = rootCA.SignCertificate(certDir, testName, ecPubKey) + assert.NoError(t, err, "Failed to generate signed certificate") + + // check to make sure the signed public key was stored + pemFile := filepath.Join(certDir, testName+"-cert.pem") + assert.Equal(t, true, checkForFile(pemFile), + "Expected to find file "+pemFile) + cleanup(testDir) + +} + +func cleanup(dir string) { + os.RemoveAll(dir) +} + +func checkForFile(file string) bool { + if _, err := os.Stat(file); os.IsNotExist(err) { + return false + } + return true +} diff --git a/common/tools/cryptogen/ca/generator.go b/common/tools/cryptogen/ca/generator.go new file mode 100644 index 00000000000..b98654452ef --- /dev/null +++ b/common/tools/cryptogen/ca/generator.go @@ -0,0 +1,181 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package ca + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "os" + "time" + + "path/filepath" + + "github.com/hyperledger/fabric/common/tools/cryptogen/csp" +) + +type CA struct { + Name string + //SignKey *ecdsa.PrivateKey + Signer crypto.Signer + SignCert *x509.Certificate +} + +// NewCA creates an instance of CA and saves the signing key pair in +// baseDir/name +func NewCA(baseDir, name string) (*CA, error) { + + err := os.MkdirAll(baseDir, 0755) + if err != nil { + return nil, err + } + + //key, err := genKeyECDSA(caDir, name) + priv, signer, err := csp.GeneratePrivateKey(baseDir) + // get public signing certificate + ecPubKey, err := csp.GetECPublicKey(priv) + if err != nil { + return nil, err + } + + template, err := x509Template() + + if err != nil { + return nil, err + } + + //this is a CA + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign | x509.KeyUsageCRLSign + template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny} + + //set the organization for the subject + subject := subjectTemplate() + subject.Organization = []string{name} + subject.CommonName = name + + template.Subject = subject + template.SubjectKeyId = priv.SKI() + + x509Cert, err := genCertificateECDSA(baseDir, name, &template, &template, + ecPubKey, signer) + + if err != nil { + return nil, err + } + + ca := &CA{ + Name: name, + Signer: signer, + SignCert: x509Cert, + } + + return ca, nil +} + +// SignCertificate creates a signed certificate based on a built-in template +// and saves it in baseDir/name +func (ca *CA) SignCertificate(baseDir, name string, pub *ecdsa.PublicKey) error { + + template, err := x509Template() + + if err != nil { + return err + } + + template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} + + //set the organization for the subject + subject := subjectTemplate() + subject.CommonName = name + + template.Subject = subject + + _, err = genCertificateECDSA(baseDir, name, &template, ca.SignCert, + pub, ca.Signer) + + if err != nil { + return err + } + + return nil +} + +// default template for X509 subject +func subjectTemplate() pkix.Name { + return pkix.Name{ + Country: []string{"US"}, + Locality: []string{"San Francisco"}, + Province: []string{"California"}, + } +} + +// default template for X509 certificates +func x509Template() (x509.Certificate, error) { + + //generate a serial number + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return x509.Certificate{}, err + } + + now := time.Now() + //basic template to use + x509 := x509.Certificate{ + SerialNumber: serialNumber, + NotBefore: now, + NotAfter: now.Add(3650 * 24 * time.Hour), //~ten years + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + BasicConstraintsValid: true, + } + return x509, nil + +} + +// generate a signed X509 certficate using ECDSA +func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey, + priv interface{}) (*x509.Certificate, error) { + + //create the x509 public cert + certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv) + if err != nil { + return nil, err + } + + //write cert out to file + fileName := filepath.Join(baseDir, name+"-cert.pem") + certFile, err := os.Create(fileName) + if err != nil { + return nil, err + } + //pem encode the cert + err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) + certFile.Close() + if err != nil { + return nil, err + } + + x509Cert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, err + } + return x509Cert, nil +} diff --git a/common/tools/cryptogen/csp/csp.go b/common/tools/cryptogen/csp/csp.go new file mode 100644 index 00000000000..44e5a2c875f --- /dev/null +++ b/common/tools/cryptogen/csp/csp.go @@ -0,0 +1,79 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package csp + +import ( + "crypto" + "crypto/ecdsa" + "crypto/x509" + + "github.com/hyperledger/fabric/bccsp" + "github.com/hyperledger/fabric/bccsp/factory" + "github.com/hyperledger/fabric/bccsp/signer" + "github.com/hyperledger/fabric/bccsp/sw" +) + +// GeneratePrivateKey creates a private key and stores it in keystorePath +func GeneratePrivateKey(keystorePath string) (bccsp.Key, + crypto.Signer, error) { + + csp := factory.GetDefault() + + // generate a key + priv, err := csp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true}) + if err != nil { + return nil, nil, err + } + // write it to the keystore + ks, err := sw.NewFileBasedKeyStore(nil, keystorePath, false) + if err != nil { + return nil, nil, err + } + err = ks.StoreKey(priv) + if err != nil { + return nil, nil, err + } + + // create a crypto.Signer + signer := &signer.CryptoSigner{} + err = signer.Init(csp, priv) + if err != nil { + return nil, nil, err + } + + return priv, signer, nil + +} + +func GetECPublicKey(priv bccsp.Key) (*ecdsa.PublicKey, error) { + + // get the public key + pubKey, err := priv.PublicKey() + if err != nil { + return nil, err + } + // marshal to bytes + pubKeyBytes, err := pubKey.Bytes() + if err != nil { + return nil, err + } + // unmarshal using pkix + ecPubKey, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return nil, err + } + return ecPubKey.(*ecdsa.PublicKey), nil +} diff --git a/common/tools/cryptogen/csp/csp_test.go b/common/tools/cryptogen/csp/csp_test.go new file mode 100644 index 00000000000..7f6cad6ca7b --- /dev/null +++ b/common/tools/cryptogen/csp/csp_test.go @@ -0,0 +1,67 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package csp_test + +import ( + "crypto/ecdsa" + "encoding/hex" + "os" + "path/filepath" + "testing" + + "github.com/hyperledger/fabric/common/tools/cryptogen/csp" + "github.com/stretchr/testify/assert" +) + +var testDir = filepath.Join(os.TempDir(), "csp-test") + +func TestGeneratePrivateKey(t *testing.T) { + + priv, signer, err := csp.GeneratePrivateKey(testDir) + assert.NoError(t, err, "Failed to generate private key") + assert.NotNil(t, priv, "Should have returned a bccsp.Key") + assert.Equal(t, true, priv.Private(), "Failed to return private key") + assert.NotNil(t, signer, "Should have returned a crypto.Signer") + pkFile := filepath.Join(testDir, hex.EncodeToString(priv.SKI())+"_sk") + t.Log(pkFile) + assert.Equal(t, true, checkForFile(pkFile), + "Expected to find private key file") + cleanup(testDir) + +} + +func TestGetECPublicKey(t *testing.T) { + + priv, _, err := csp.GeneratePrivateKey(testDir) + assert.NoError(t, err, "Failed to generate private key") + + ecPubKey, err := csp.GetECPublicKey(priv) + assert.NoError(t, err, "Failed to get public key from private key") + assert.IsType(t, &ecdsa.PublicKey{}, ecPubKey, + "Failed to return an ecdsa.PublicKey") + cleanup(testDir) +} + +func cleanup(dir string) { + os.RemoveAll(dir) +} + +func checkForFile(file string) bool { + if _, err := os.Stat(file); os.IsNotExist(err) { + return false + } + return true +} diff --git a/common/tools/cryptogen/main.go b/common/tools/cryptogen/main.go new file mode 100644 index 00000000000..a6f414db26b --- /dev/null +++ b/common/tools/cryptogen/main.go @@ -0,0 +1,152 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + + "github.com/hyperledger/fabric/common/tools/cryptogen/ca" + "github.com/hyperledger/fabric/common/tools/cryptogen/msp" +) + +const ( + peerOrgBaseName = "peerOrg" + peerBaseName = "Peer" + orderOrgBaseName = "ordererOrg" + ordererBaseName = "orderer" +) + +//command line flags +var ( + numPeerOrgs = flag.Int("peerOrgs", 2, + "number of unique organizations with peers") + numPeers = flag.Int("peersPerOrg", 1, + "number of peers per organization") + numOrderers = flag.Int("ordererNodes", 1, + "number of ordering service nodes") + baseDir = flag.String("baseDir", ".", + "directory in which to place artifacts") +) + +var numOrdererOrgs = 1 + +func main() { + flag.Parse() + + if flag.NFlag() == 0 { + fmt.Println("\nYou must specify at least one parameter") + flag.Usage() + os.Exit(1) + } + + genDir := filepath.Join(*baseDir, "crypto-config") + if *numPeerOrgs > 0 { + fmt.Printf("Generating %d peer organization(s) each with %d peer(s) ...\n", + *numPeerOrgs, *numPeers) + + // TODO: add ability to specify peer org names + // for name just use default base name + peerOrgNames := []string{} + for i := 1; i <= *numPeerOrgs; i++ { + peerOrgNames = append(peerOrgNames, fmt.Sprintf("%s%d", peerOrgBaseName, i)) + } + generatePeerOrgs(genDir, peerOrgNames) + + } + + if *numOrderers > 0 { + fmt.Printf("Generating %d orderer organization(s) and %d ordering node(s) ...\n", + numOrdererOrgs, *numOrderers) + generateOrdererOrg(genDir, fmt.Sprintf("%s1", orderOrgBaseName)) + } + +} + +func generatePeerOrgs(baseDir string, orgNames []string) { + + for _, orgName := range orgNames { + fmt.Println(orgName) + // generate CA + orgDir := filepath.Join(baseDir, "peerOrganizations", orgName) + caDir := filepath.Join(orgDir, "ca") + mspDir := filepath.Join(orgDir, "msp") + peersDir := filepath.Join(orgDir, "peers") + rootCA, err := ca.NewCA(caDir, orgName) + if err != nil { + fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err) + os.Exit(1) + } + err = msp.GenerateVerifyingMSP(mspDir, rootCA) + if err != nil { + fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) + os.Exit(1) + } + + // TODO: add ability to specify peer names + // for name just use default base name + peerNames := []string{} + for i := 1; i <= *numPeerOrgs; i++ { + peerNames = append(peerNames, fmt.Sprintf("%s%s%d", + orgName, peerBaseName, i)) + } + generateNodes(peersDir, peerNames, rootCA) + } +} + +func generateNodes(baseDir string, nodeNames []string, rootCA *ca.CA) { + + for _, nodeName := range nodeNames { + nodeDir := filepath.Join(baseDir, nodeName) + err := msp.GenerateLocalMSP(nodeDir, nodeName, rootCA) + if err != nil { + fmt.Printf("Error generating local MSP for %s:\n%v\n", nodeName, err) + os.Exit(1) + } + } + +} + +func generateOrdererOrg(baseDir, orgName string) { + + // generate CA + orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName) + caDir := filepath.Join(orgDir, "ca") + mspDir := filepath.Join(orgDir, "msp") + orderersDir := filepath.Join(orgDir, "orderers") + rootCA, err := ca.NewCA(caDir, orgName) + if err != nil { + fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err) + os.Exit(1) + } + err = msp.GenerateVerifyingMSP(mspDir, rootCA) + if err != nil { + fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) + os.Exit(1) + } + + // TODO: add ability to specify orderer names + // for name just use default base name + ordererNames := []string{} + for i := 1; i <= *numOrderers; i++ { + ordererNames = append(ordererNames, fmt.Sprintf("%s%s%d", + orgName, ordererBaseName, i)) + } + generateNodes(orderersDir, ordererNames, rootCA) + +} diff --git a/common/tools/cryptogen/msp/generator.go b/common/tools/cryptogen/msp/generator.go new file mode 100644 index 00000000000..e13e54af123 --- /dev/null +++ b/common/tools/cryptogen/msp/generator.go @@ -0,0 +1,127 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package msp + +import ( + "crypto/x509" + "encoding/pem" + "os" + "path/filepath" + + "github.com/hyperledger/fabric/common/tools/cryptogen/ca" + "github.com/hyperledger/fabric/common/tools/cryptogen/csp" +) + +func GenerateLocalMSP(baseDir, name string, rootCA *ca.CA) error { + + // create folder structure + err := createFolderStructure(baseDir) + if err != nil { + return err + } + + // generate private key + priv, _, err := csp.GeneratePrivateKey(filepath.Join(baseDir, "keystore")) + if err != nil { + return err + } + + // get public signing certificate + ecPubKey, err := csp.GetECPublicKey(priv) + if err != nil { + return err + } + err = rootCA.SignCertificate(filepath.Join(baseDir, "signcerts"), + name, ecPubKey) + if err != nil { + return err + } + + // write root cert to folders + err = x509ToFile(filepath.Join(baseDir, "admincerts"), rootCA.Name, rootCA.SignCert) + if err != nil { + return err + } + err = x509ToFile(filepath.Join(baseDir, "cacerts"), rootCA.Name, rootCA.SignCert) + if err != nil { + return err + } + return nil + +} + +func GenerateVerifyingMSP(baseDir string, rootCA *ca.CA) error { + + // create folder structure + err := createFolderStructure(baseDir) + if err != nil { + return err + } + + // write public cert to appropriate folders + err = x509ToFile(filepath.Join(baseDir, "admincerts"), rootCA.Name, rootCA.SignCert) + if err != nil { + return err + } + err = x509ToFile(filepath.Join(baseDir, "cacerts"), rootCA.Name, rootCA.SignCert) + if err != nil { + return err + } + err = x509ToFile(filepath.Join(baseDir, "signcerts"), rootCA.Name, rootCA.SignCert) + if err != nil { + return err + } + + return nil +} + +func createFolderStructure(rootDir string) error { + + // create admincerts, cacerts, keystore and signcerts folders + folders := []string{ + filepath.Join(rootDir, "admincerts"), + filepath.Join(rootDir, "cacerts"), + filepath.Join(rootDir, "keystore"), + filepath.Join(rootDir, "signcerts"), + } + + for _, folder := range folders { + err := os.MkdirAll(folder, 0755) + if err != nil { + return err + } + } + return nil +} + +func x509ToFile(baseDir, name string, cert *x509.Certificate) error { + + //write cert out to file + fileName := filepath.Join(baseDir, name+"-cert.pem") + certFile, err := os.Create(fileName) + if err != nil { + return err + } + //pem encode the cert + err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) + certFile.Close() + if err != nil { + return err + } + + return nil + +} diff --git a/common/tools/cryptogen/msp/msp_test.go b/common/tools/cryptogen/msp/msp_test.go new file mode 100644 index 00000000000..f41f646679d --- /dev/null +++ b/common/tools/cryptogen/msp/msp_test.go @@ -0,0 +1,109 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package msp_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/hyperledger/fabric/common/tools/cryptogen/ca" + "github.com/hyperledger/fabric/common/tools/cryptogen/msp" + fabricmsp "github.com/hyperledger/fabric/msp" + "github.com/stretchr/testify/assert" +) + +const ( + testCAName = "root0" + testName = "peer0" +) + +var testDir = filepath.Join(os.TempDir(), "msp-test") + +func TestGenerateLocalMSP(t *testing.T) { + + cleanup(testDir) + caDir := filepath.Join(testDir, "ca") + mspDir := filepath.Join(testDir, "msp") + rootCA, err := ca.NewCA(caDir, testCAName) + assert.NoError(t, err, "Error generating CA") + err = msp.GenerateLocalMSP(mspDir, testName, rootCA) + assert.NoError(t, err, "Failed to generate local MSP") + + // check to see that the right files were generated/saved + files := []string{ + filepath.Join(mspDir, "admincerts", testCAName+"-cert.pem"), + filepath.Join(mspDir, "cacerts", testCAName+"-cert.pem"), + filepath.Join(mspDir, "keystore"), + filepath.Join(mspDir, "signcerts", testName+"-cert.pem"), + } + + for _, file := range files { + assert.Equal(t, true, checkForFile(file), + "Expected to find file "+file) + } + + // finally check to see if we can load this as a local MSP config + testMSPConfig, err := fabricmsp.GetLocalMspConfig(mspDir, nil, testName) + assert.NoError(t, err, "Error parsing local MSP config") + testMSP, err := fabricmsp.NewBccspMsp() + assert.NoError(t, err, "Error creating new BCCSP MSP") + err = testMSP.Setup(testMSPConfig) + assert.NoError(t, err, "Error setting up local MSP") + cleanup(testDir) + +} + +func TestGenerateVerifyingMSP(t *testing.T) { + + caDir := filepath.Join(testDir, "ca") + mspDir := filepath.Join(testDir, "msp") + rootCA, err := ca.NewCA(caDir, testCAName) + + err = msp.GenerateVerifyingMSP(mspDir, rootCA) + assert.NoError(t, err, "Failed to generate verifying MSP") + + // check to see that the right files were generated/saved + files := []string{ + filepath.Join(mspDir, "admincerts", testCAName+"-cert.pem"), + filepath.Join(mspDir, "cacerts", testCAName+"-cert.pem"), + filepath.Join(mspDir, "signcerts", testCAName+"-cert.pem"), + } + + for _, file := range files { + assert.Equal(t, true, checkForFile(file), + "Expected to find file "+file) + } + // finally check to see if we can load this as a verifying MSP config + testMSPConfig, err := fabricmsp.GetVerifyingMspConfig(mspDir, nil, testName) + assert.NoError(t, err, "Error parsing verifying MSP config") + testMSP, err := fabricmsp.NewBccspMsp() + assert.NoError(t, err, "Error creating new BCCSP MSP") + err = testMSP.Setup(testMSPConfig) + assert.NoError(t, err, "Error setting up verifying MSP") + cleanup(testDir) +} + +func cleanup(dir string) { + os.RemoveAll(dir) +} + +func checkForFile(file string) bool { + if _, err := os.Stat(file); os.IsNotExist(err) { + return false + } + return true +}