Skip to content

Commit

Permalink
Allow BCCSP config to be set using env var (hyperledger#1900)
Browse files Browse the repository at this point in the history
FAB-17969

Signed-off-by: Tiffany Harris <tiffany.harris@ibm.com>
Signed-off-by: Will Lahti <wtlahti@us.ibm.com>
  • Loading branch information
wlahti authored and ale-linux committed Oct 5, 2020
1 parent 6bd0699 commit f2e9e6e
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 90 deletions.
6 changes: 0 additions & 6 deletions bccsp/factory/nopkcs11.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ import (

const pkcs11Enabled = false

// FactoryOpts holds configuration information used to initialize factory implementations
type FactoryOpts struct {
ProviderName string `mapstructure:"default" json:"default" yaml:"Default"`
SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SW,omitempty"`
}

// InitFactories must be called before using factory interfaces
// It is acceptable to call with config = nil, in which case
// some defaults will get used
Expand Down
27 changes: 15 additions & 12 deletions bccsp/factory/opts.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Copyright IBM Corp. 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.
SPDX-License-Identifier: Apache-2.0
*/

package factory

import "github.com/hyperledger/fabric/bccsp/pkcs11"

// FactoryOpts holds configuration information used to initialize factory implementations
type FactoryOpts struct {
ProviderName string `mapstructure:"default" json:"default" yaml:"Default"`
SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SW,omitempty"`
Pkcs11Opts *pkcs11.PKCS11Opts `mapstructure:"PKCS11,omitempty" json:"PKCS11,omitempty" yaml:"PKCS11"`
}

// GetDefaultOpts offers a default implementation for Opts
// returns a new instance every time
func GetDefaultOpts() *FactoryOpts {
Expand All @@ -26,6 +25,10 @@ func GetDefaultOpts() *FactoryOpts {
SecLevel: 256,
Ephemeral: true,
},
Pkcs11Opts: &pkcs11.PKCS11Opts{
HashFamily: "SHA2",
SecLevel: 256,
},
}
}

Expand Down
8 changes: 0 additions & 8 deletions bccsp/factory/pkcs11.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,11 @@ package factory

import (
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/pkcs11"
"github.com/pkg/errors"
)

const pkcs11Enabled = false

// FactoryOpts holds configuration information used to initialize factory implementations
type FactoryOpts struct {
ProviderName string `mapstructure:"default" json:"default" yaml:"Default"`
SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SW,omitempty"`
Pkcs11Opts *pkcs11.PKCS11Opts `mapstructure:"PKCS11,omitempty" json:"PKCS11,omitempty" yaml:"PKCS11"`
}

// InitFactories must be called before using factory interfaces
// It is acceptable to call with config = nil, in which case
// some defaults will get used
Expand Down
2 changes: 1 addition & 1 deletion common/viperutil/config_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func bccspHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, e

err := mapstructure.WeakDecode(data, config)
if err != nil {
return nil, errors.Wrap(err, "could not decode bcssp type")
return nil, errors.Wrap(err, "could not decode bccsp type")
}

return config, nil
Expand Down
6 changes: 6 additions & 0 deletions integration/nwo/core_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ peer:
Security: 256
FileKeyStore:
KeyStore:
PKCS11:
Hash: SHA2
Security: 256
Library:
Label:
Pin:
mspConfigPath: {{ .PeerLocalMSPDir Peer }}
localMspId: {{ (.Organization Peer.Organization).MSPID }}
deliveryclient:
Expand Down
6 changes: 6 additions & 0 deletions integration/nwo/orderer_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ General:
Security: 256
FileKeyStore:
KeyStore:
PKCS11:
Hash: SHA2
Security: 256
Library:
Label:
Pin:
Authentication:
TimeWindow: 15m
FileLedger:
Expand Down
62 changes: 62 additions & 0 deletions integration/pkcs11/pkcs11_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/hyperledger/fabric/integration"
"github.com/hyperledger/fabric/integration/nwo"
"github.com/hyperledger/fabric/integration/nwo/commands"
"github.com/hyperledger/fabric/integration/nwo/fabricconfig"
"github.com/miekg/pkcs11"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
Expand All @@ -32,6 +34,9 @@ func TestPKCS11(t *testing.T) {
var (
buildServer *nwo.BuildServer
components *nwo.Components
ctx *pkcs11.Ctx
sess pkcs11.SessionHandle
bccspConfig *fabricconfig.BCCSP
)

var _ = SynchronizedBeforeSuite(func() []byte {
Expand All @@ -41,6 +46,9 @@ var _ = SynchronizedBeforeSuite(func() []byte {
components = buildServer.Components()
payload, err := json.Marshal(components)
Expect(err).NotTo(HaveOccurred())

setupPKCS11()

return payload
}, func(payload []byte) {
err := json.Unmarshal(payload, &components)
Expand All @@ -50,12 +58,66 @@ var _ = SynchronizedBeforeSuite(func() []byte {
var _ = SynchronizedAfterSuite(func() {
}, func() {
buildServer.Shutdown()
ctx.Destroy()
ctx.CloseSession(sess)
})

func StartPort() int {
return integration.PKCS11Port.StartPortForNode()
}

func setupPKCS11() {
lib, pin, label := bpkcs11.FindPKCS11Lib()
ctx, sess = setupPKCS11Ctx(lib, label, pin)
bccspConfig = &fabricconfig.BCCSP{
Default: "PKCS11",
PKCS11: &fabricconfig.PKCS11{
Security: 256,
Hash: "SHA2",
Pin: pin,
Label: label,
Library: lib,
},
}
}

// Creates pkcs11 context and session
func setupPKCS11Ctx(lib, label, pin string) (*pkcs11.Ctx, pkcs11.SessionHandle) {
ctx := pkcs11.New(lib)

err := ctx.Initialize()
Expect(err).NotTo(HaveOccurred())

slot := findPKCS11Slot(ctx, label)
Expect(slot).Should(BeNumerically(">", 0), "Could not find slot with label %s", label)

sess, err := ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
Expect(err).NotTo(HaveOccurred())

// Login
err = ctx.Login(sess, pkcs11.CKU_USER, pin)
Expect(err).NotTo(HaveOccurred())

return ctx, sess
}

// Identifies pkcs11 slot using specified label
func findPKCS11Slot(ctx *pkcs11.Ctx, label string) uint {
slots, err := ctx.GetSlotList(true)
Expect(err).NotTo(HaveOccurred())

for _, s := range slots {
tokInfo, err := ctx.GetTokenInfo(s)
Expect(err).NotTo(HaveOccurred())

if tokInfo.Label == label {
return s
}
}

return 0
}

func runQueryInvokeQuery(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, channel string) {
By("querying the chaincode")
sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeQuery{
Expand Down
138 changes: 75 additions & 63 deletions integration/pkcs11/pkcs11_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import (
"math/big"
"os"
"path/filepath"
"strconv"
"syscall"
"time"

bpkcs11 "github.com/hyperledger/fabric/bccsp/pkcs11"
"github.com/hyperledger/fabric/integration/nwo"
"github.com/hyperledger/fabric/integration/nwo/fabricconfig"
"github.com/miekg/pkcs11"
Expand All @@ -50,12 +50,7 @@ var _ = Describe("PKCS11 enabled network", func() {
network.Bootstrap()

By("configuring PKCS11 artifacts")
setupPKCS11(network)

By("starting fabric processes")
networkRunner := network.NetworkGroupRunner()
process = ifrit.Invoke(networkRunner)
Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
configurePKCS11(network)
})

AfterEach(func() {
Expand All @@ -67,7 +62,14 @@ var _ = Describe("PKCS11 enabled network", func() {
os.RemoveAll(tempDir)
})

It("executes transactions against a basic solo network", func() {
It("executes transactions against a basic solo network using yaml config", func() {
setPKCS11Config(network, bccspConfig)

By("starting fabric processes")
networkRunner := network.NetworkGroupRunner()
process = ifrit.Invoke(networkRunner)
Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())

chaincode := nwo.Chaincode{
Name: "mycc",
Version: "0.0",
Expand All @@ -88,30 +90,44 @@ var _ = Describe("PKCS11 enabled network", func() {
nwo.DeployChaincode(network, "testchannel", orderer, chaincode)
runQueryInvokeQuery(network, orderer, network.Peer("Org1", "peer0"), "testchannel")
})
})

func setupPKCS11(network *nwo.Network) {
lib, pin, label := bpkcs11.FindPKCS11Lib()
It("executes transactions against a basic solo network using environment variable config", func() {
envCleanup := setPKCS11ConfigWithEnvVariables(network, bccspConfig)
defer envCleanup()

By("starting fabric processes")
networkRunner := network.NetworkGroupRunner()
process = ifrit.Invoke(networkRunner)
Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())

chaincode := nwo.Chaincode{
Name: "mycc",
Version: "0.0",
Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/simple/cmd"),
Lang: "binary",
PackageFile: filepath.Join(tempDir, "simplecc.tar.gz"),
Ctor: `{"Args":["init","a","100","b","200"]}`,
SignaturePolicy: `AND ('Org1MSP.member','Org2MSP.member')`,
Sequence: "1",
InitRequired: true,
Label: "my_prebuilt_chaincode",
}

orderer := network.Orderer("orderer")
network.CreateAndJoinChannels(orderer)

By("establishing a PKCS11 session")
ctx, sess := setupPKCS11Ctx(lib, label, pin)
defer ctx.Destroy()
defer ctx.CloseSession(sess)
nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.PeersWithChannel("testchannel")...)
nwo.DeployChaincode(network, "testchannel", orderer, chaincode)
runQueryInvokeQuery(network, orderer, network.Peer("Org1", "peer0"), "testchannel")
})
})

func configurePKCS11(network *nwo.Network) {
configurePeerPKCS11(ctx, sess, network)
configureOrdererPKCS11(ctx, sess, network)
}

bccspConfig := &fabricconfig.BCCSP{
Default: "PKCS11",
PKCS11: &fabricconfig.PKCS11{
Security: 256,
Hash: "SHA2",
Pin: pin,
Label: label,
Library: lib,
},
}

func setPKCS11Config(network *nwo.Network, bccspConfig *fabricconfig.BCCSP) {
By("updating bccsp peer config")
for _, peer := range network.Peers {
peerConfig := network.ReadPeerConfig(peer)
Expand All @@ -126,6 +142,39 @@ func setupPKCS11(network *nwo.Network) {
network.WriteOrdererConfig(orderer, ordererConfig)
}

func setPKCS11ConfigWithEnvVariables(network *nwo.Network, bccspConfig *fabricconfig.BCCSP) (cleanup func()) {
By("setting bccsp peer config via environment variables")
os.Setenv("CORE_PEER_BCCSP_DEFAULT", bccspConfig.Default)
os.Setenv("CORE_PEER_BCCSP_PKCS11_SECURITY", strconv.Itoa(bccspConfig.PKCS11.Security))
os.Setenv("CORE_PEER_BCCSP_PKCS11_HASH", bccspConfig.PKCS11.Hash)
os.Setenv("CORE_PEER_BCCSP_PKCS11_PIN", bccspConfig.PKCS11.Pin)
os.Setenv("CORE_PEER_BCCSP_PKCS11_LABEL", bccspConfig.PKCS11.Label)
os.Setenv("CORE_PEER_BCCSP_PKCS11_LIBRARY", bccspConfig.PKCS11.Library)

By("setting bccsp orderer config via environment variables")
os.Setenv("ORDERER_GENERAL_BCCSP_DEFAULT", bccspConfig.Default)
os.Setenv("ORDERER_GENERAL_BCCSP_PKCS11_SECURITY", strconv.Itoa(bccspConfig.PKCS11.Security))
os.Setenv("ORDERER_GENERAL_BCCSP_PKCS11_HASH", bccspConfig.PKCS11.Hash)
os.Setenv("ORDERER_GENERAL_BCCSP_PKCS11_PIN", bccspConfig.PKCS11.Pin)
os.Setenv("ORDERER_GENERAL_BCCSP_PKCS11_LABEL", bccspConfig.PKCS11.Label)
os.Setenv("ORDERER_GENERAL_BCCSP_PKCS11_LIBRARY", bccspConfig.PKCS11.Library)

return func() {
os.Unsetenv("CORE_PEER_BCCSP_DEFAULT")
os.Unsetenv("CORE_PEER_BCCSP_PKCS11_SECURITY")
os.Unsetenv("CORE_PEER_BCCSP_PKCS11_HASH")
os.Unsetenv("CORE_PEER_BCCSP_PKCS11_PIN")
os.Unsetenv("CORE_PEER_BCCSP_PKCS11_LABEL")
os.Unsetenv("CORE_PEER_BCCSP_PKCS11_LIBRARY")
os.Unsetenv("ORDERER_GENERAL_BCCSP_DEFAULT")
os.Unsetenv("ORDERER_GENERAL_BCCSP_PKCS11_SECURITY")
os.Unsetenv("ORDERER_GENERAL_BCCSP_PKCS11_HASH")
os.Unsetenv("ORDERER_GENERAL_BCCSP_PKCS11_PIN")
os.Unsetenv("ORDERER_GENERAL_BCCSP_PKCS11_LABEL")
os.Unsetenv("ORDERER_GENERAL_BCCSP_PKCS11_LIBRARY")
}
}

func configurePeerPKCS11(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle, network *nwo.Network) {
for _, peer := range network.Peers {
orgName := peer.Organization
Expand Down Expand Up @@ -180,43 +229,6 @@ func configureOrdererPKCS11(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle, network
updateMSPFolder(orgAdminMSPPath, fmt.Sprintf("Admin@%s-cert.pem", domain), newAdminPemCert)
}

// Creates pkcs11 context and session
func setupPKCS11Ctx(lib, label, pin string) (*pkcs11.Ctx, pkcs11.SessionHandle) {
ctx := pkcs11.New(lib)

err := ctx.Initialize()
Expect(err).NotTo(HaveOccurred())

slot := findPKCS11Slot(ctx, label)
Expect(slot).Should(BeNumerically(">", 0), "Could not find slot with label %s", label)

sess, err := ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
Expect(err).NotTo(HaveOccurred())

// Login
err = ctx.Login(sess, pkcs11.CKU_USER, pin)
Expect(err).NotTo(HaveOccurred())

return ctx, sess
}

// Identifies pkcs11 slot using specified label
func findPKCS11Slot(ctx *pkcs11.Ctx, label string) uint {
slots, err := ctx.GetSlotList(true)
Expect(err).NotTo(HaveOccurred())

for _, s := range slots {
tokInfo, err := ctx.GetTokenInfo(s)
Expect(err).NotTo(HaveOccurred())

if tokInfo.Label == label {
return s
}
}

return 0
}

// Creates CSR for provided organization and organizational unit
func createCSR(ctx *pkcs11.Ctx, sess pkcs11.SessionHandle, org, ou string) (*ecdsa.PublicKey, *x509.CertificateRequest, *big.Int) {
pubKey, pkcs11Key := generateKeyPair(ctx, sess)
Expand Down
Loading

0 comments on commit f2e9e6e

Please sign in to comment.