Skip to content

Commit

Permalink
Merge "Orderer Signer MSP-based implementation"
Browse files Browse the repository at this point in the history
  • Loading branch information
yacovm authored and Gerrit Code Review committed Jan 19, 2017
2 parents ba3acdc + 958a66f commit add2776
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 48 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ build/image/peer/payload: build/docker/bin/peer \
build/msp-sampleconfig.tar.bz2 \
build/genesis-sampleconfig.tar.bz2
build/image/orderer/payload: build/docker/bin/orderer \
build/msp-sampleconfig.tar.bz2 \
orderer/orderer.yaml
build/image/testenv/payload: build/gotools.tar.bz2
build/image/runtime/payload: build/docker/busybox
Expand Down
28 changes: 28 additions & 0 deletions common/crypto/signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright IBM Corp. 2016 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 crypto

import cb "github.com/hyperledger/fabric/protos/common"

// LocalSigner is a temporary stub interface which will be implemented by the local MSP
type LocalSigner interface {
// NewSignatureHeader creates a SignatureHeader with the correct signing identity and a valid nonce
NewSignatureHeader() (*cb.SignatureHeader, error)

// Sign a message which should embed a signature header created by NewSignatureHeader
Sign(message []byte) ([]byte, error)
}
75 changes: 75 additions & 0 deletions common/localmsp/signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright IBM Corp. 2016 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 localmsp

import (
"fmt"

"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/hyperledger/fabric/common/crypto"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/core/peer/msp"
)

type mspSigner struct {
}

// New returns a new instance of the msp-based LocalSigner.
// It assumes that the local msp has been already initialized.
// Look at mspmgmt.LoadLocalMsp for further information.
func NewSigner() crypto.LocalSigner {
return &mspSigner{}
}

// NewSignatureHeader creates a SignatureHeader with the correct signing identity and a valid nonce
func (s *mspSigner) NewSignatureHeader() (*cb.SignatureHeader, error) {
signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
if err != nil {
return nil, fmt.Errorf("Failed getting MSP-based signer [%s]", err)
}

creatorIdentityRaw, err := signer.Serialize()
if err != nil {
return nil, fmt.Errorf("Failed serializing creator public identity [%s]", err)
}

nonce, err := primitives.GetRandomNonce()
if err != nil {
return nil, fmt.Errorf("Failed creating nonce [%s]", err)
}

sh := &cb.SignatureHeader{}
sh.Creator = creatorIdentityRaw
sh.Nonce = nonce

return sh, nil
}

// Sign a message which should embed a signature header created by NewSignatureHeader
func (s *mspSigner) Sign(message []byte) ([]byte, error) {
signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
if err != nil {
return nil, fmt.Errorf("Failed getting MSP-based signer [%s]", err)
}

signature, err := signer.Sign(message)
if err != nil {
return nil, fmt.Errorf("Failed generating signature [%s]", err)
}

return signature, nil
}
84 changes: 84 additions & 0 deletions common/localmsp/signer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright IBM Corp. 2016 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 localmsp

import (
"os"
"testing"

"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/stretchr/testify/assert"
"github.com/hyperledger/fabric/core/peer/msp"
)

func TestMain(m *testing.M) {
// 1. Determine MSP configuration
var mspMgrConfigDir string
var alternativeCfgPath = os.Getenv("ORDERER_CFG_PATH")
if alternativeCfgPath != "" {
mspMgrConfigDir = alternativeCfgPath + "/msp/sampleconfig/"
} else if _, err := os.Stat("./msp/sampleconfig/"); err == nil {
mspMgrConfigDir = "./msp/sampleconfig/"
} else {
mspMgrConfigDir = os.Getenv("GOPATH") + "/src/github.com/hyperledger/fabric/msp/sampleconfig/"
}

if err := mspmgmt.LoadLocalMsp(mspMgrConfigDir); err != nil {
os.Exit(-1)
}

os.Exit(m.Run())
}

func TestNewSigner(t *testing.T) {
signer := NewSigner()
assert.NotNil(t, signer, "Signer must be differentr from nil.")
}

func TestMspSigner_NewSignatureHeader(t *testing.T) {
signer := NewSigner()

sh, err := signer.NewSignatureHeader()
if err != nil {
t.Fatalf("Failed creting signature header [%s]", err)
}

assert.NotNil(t, sh, "SignatureHeader must be different from nil")
assert.Len(t, sh.Nonce, primitives.NonceSize, "SignatureHeader.Nonce must be of length %d", primitives.NonceSize)

mspIdentity, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
assert.NoError(t, err, "Failed getting default MSP Identity")
publicIdentity := mspIdentity.GetPublicVersion()
assert.NotNil(t, publicIdentity, "Failed getting default public identity. It must be different from nil.")
publicIdentityRaw, err := publicIdentity.Serialize()
assert.NoError(t, err, "Failed serializing default public identity")
assert.Equal(t, publicIdentityRaw, sh.Creator, "Creator must be local default signer identity")
}

func TestMspSigner_Sign(t *testing.T) {
signer := NewSigner()

msg := []byte("Hello World")
sigma, err := signer.Sign(msg)
assert.NoError(t, err, "FAiled generating signature")

// Verify signature
mspIdentity, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
assert.NoError(t, err, "Failed getting default MSP Identity")
err = mspIdentity.Verify(msg, sigma)
assert.NoError(t, err, "Failed verifiing signature")
}
7 changes: 4 additions & 3 deletions images/orderer/Dockerfile.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
FROM hyperledger/fabric-runtime:_TAG_
ENV ORDERER_CFG_PATH /etc/hyperledger/fabric
RUN mkdir -p /var/hyperledger/db /etc/hyperledger/fabric
ENV ORDERER_CFG_PATH /etc/hyperledger/fabric/orderer
RUN mkdir -p /var/hyperledger/db /etc/hyperledger/fabric/orderer
COPY payload/orderer /usr/local/bin
COPY payload/orderer.yaml $ORDERER_CFG_PATH
ADD payload/msp-sampleconfig.tar.bz2 $ORDERER_CFG_PATH/../
COPY payload/orderer.yaml $ORDERER_CFG_PATH/
EXPOSE 7050
CMD orderer
34 changes: 23 additions & 11 deletions orderer/localconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type General struct {
GenesisFile string
Profile Profile
LogLevel string
LocalMSPDir string
}

// Genesis contains config which is used by the provisional bootstrapper
Expand Down Expand Up @@ -121,7 +122,8 @@ var defaults = TopLevel{
Enabled: false,
Address: "0.0.0.0:6060",
},
LogLevel: "INFO",
LogLevel: "INFO",
LocalMSPDir: "../msp/sampleconfig/",
},
RAMLedger: RAMLedger{
HistorySize: 10000,
Expand Down Expand Up @@ -180,6 +182,12 @@ func (c *TopLevel) completeInitialization() {
case c.General.Profile.Enabled && (c.General.Profile.Address == ""):
logger.Infof("Profiling enabled and General.Profile.Address unset, setting to %s", defaults.General.Profile.Address)
c.General.Profile.Address = defaults.General.Profile.Address
case c.General.LocalMSPDir == "":
logger.Infof("General.LocalMSPDir unset, setting to %s", defaults.General.LocalMSPDir)
// Note, this is a bit of a weird one, the orderer may set the ORDERER_CFG_PATH after
// the file is initialized, so we cannot initialize this in the structure, so we
// deference the env portion here
c.General.LocalMSPDir = filepath.Join(os.Getenv("ORDERER_CFG_PATH"), defaults.General.LocalMSPDir)
case c.FileLedger.Prefix == "":
logger.Infof("FileLedger.Prefix unset, setting to %s", defaults.FileLedger.Prefix)
c.FileLedger.Prefix = defaults.FileLedger.Prefix
Expand Down Expand Up @@ -221,22 +229,26 @@ func Load() *TopLevel {
config := viper.New()

config.SetConfigName("orderer")
alternativeCfgPath := os.Getenv("ORDERER_CFG_PATH")
if alternativeCfgPath != "" {
logger.Infof("User defined config file path: %s", alternativeCfgPath)
config.AddConfigPath(alternativeCfgPath) // Path to look for the config file in
} else {
config.AddConfigPath("./")
config.AddConfigPath("../../.")
config.AddConfigPath("../orderer/")
config.AddConfigPath("../../orderer/")
cfgPath := os.Getenv("ORDERER_CFG_PATH")
if cfgPath == "" {
logger.Infof("No orderer cfg path set, assuming development environment, deriving from go path")
// Path to look for the config file in based on GOPATH
gopath := os.Getenv("GOPATH")
for _, p := range filepath.SplitList(gopath) {
ordererPath := filepath.Join(p, "src/github.com/hyperledger/fabric/orderer/")
config.AddConfigPath(ordererPath)
if _, err := os.Stat(filepath.Join(ordererPath, "orderer.yaml")); err != nil {
// The yaml file does not exist in this component of the go src
continue
}
cfgPath = ordererPath
}
if cfgPath == "" {
logger.Fatalf("Could not find orderer.yaml, try setting ORDERER_CFG_PATH or GOPATH correctly")
}
logger.Infof("Setting ORDERER_CFG_PATH to: %s", cfgPath)
os.Setenv("ORDERER_CFG_PATH", cfgPath)
}
config.AddConfigPath(cfgPath) // Path to look for the config file in

// for environment variables
config.SetEnvPrefix(Prefix)
Expand Down
12 changes: 11 additions & 1 deletion orderer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,17 @@ import (
"github.com/hyperledger/fabric/protos/utils"

"github.com/Shopify/sarama"
"github.com/hyperledger/fabric/common/localmsp"
"github.com/hyperledger/fabric/core/peer/msp"
logging "github.com/op/go-logging"
"google.golang.org/grpc"
)

var logger = logging.MustGetLogger("orderer/main")

func main() {
// Temporarilly set logging level until config is read
logging.SetLevel(logging.INFO, "")
conf := config.Load()
flogging.InitFromSpec(conf.General.LogLevel)

Expand All @@ -67,6 +71,12 @@ func main() {
return
}

// Load local MSP
err = mspmgmt.LoadLocalMsp(conf.General.LocalMSPDir)
if err != nil { // Handle errors reading the config file
panic(fmt.Errorf("Failed initializing crypto [%s]", err))
}

var lf ordererledger.Factory
switch conf.General.LedgerType {
case "file":
Expand Down Expand Up @@ -127,7 +137,7 @@ func main() {
consenters["solo"] = solo.New()
consenters["kafka"] = kafka.New(conf.Kafka.Version, conf.Kafka.Retry)

manager := multichain.NewManagerImpl(lf, consenters)
manager := multichain.NewManagerImpl(lf, consenters, localmsp.NewSigner())

server := NewServer(
manager,
Expand Down
8 changes: 4 additions & 4 deletions orderer/mocks/multichain/multichain.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ func (mcs *ConsenterSupport) ChainID() string {
}

// Sign returns the bytes passed in
func (mcs *ConsenterSupport) Sign(message []byte) []byte {
return message
func (mcs *ConsenterSupport) Sign(message []byte) ([]byte, error) {
return message, nil
}

// NewSignatureHeader returns an empty signature header
func (mcs *ConsenterSupport) NewSignatureHeader() *cb.SignatureHeader {
return &cb.SignatureHeader{}
func (mcs *ConsenterSupport) NewSignatureHeader() (*cb.SignatureHeader, error) {
return &cb.SignatureHeader{}, nil
}
Loading

0 comments on commit add2776

Please sign in to comment.