Skip to content

Commit 958a66f

Browse files
author
Jason Yellick
committed
Orderer Signer MSP-based implementation
This change-set introduces an MSP-based orderer multichain.signer implementation. At bootstrap, an orderer loads his local signing identity that is then used to sign messages by means of the multichain.Signer interface. This change-set comes in the context of https://jira.hyperledger.org/browse/FAB-1268 Also updates the orderer config path stuff to be slightly more consistent to support referencing the msp sampleconfig both from the dev env and the docker image. Change-Id: Ie4e04cb18d0f28ce801a474a3c500d4f61fa9c7f Signed-off-by: Angelo De Caro <[email protected]> Signed-off-by: Jason Yellick <[email protected]>
1 parent 1b9bb80 commit 958a66f

File tree

12 files changed

+282
-48
lines changed

12 files changed

+282
-48
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ build/image/peer/payload: build/docker/bin/peer \
187187
build/msp-sampleconfig.tar.bz2 \
188188
build/genesis-sampleconfig.tar.bz2
189189
build/image/orderer/payload: build/docker/bin/orderer \
190+
build/msp-sampleconfig.tar.bz2 \
190191
orderer/orderer.yaml
191192
build/image/testenv/payload: build/gotools.tar.bz2
192193
build/image/runtime/payload: build/docker/busybox

common/crypto/signer.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package crypto
18+
19+
import cb "github.com/hyperledger/fabric/protos/common"
20+
21+
// LocalSigner is a temporary stub interface which will be implemented by the local MSP
22+
type LocalSigner interface {
23+
// NewSignatureHeader creates a SignatureHeader with the correct signing identity and a valid nonce
24+
NewSignatureHeader() (*cb.SignatureHeader, error)
25+
26+
// Sign a message which should embed a signature header created by NewSignatureHeader
27+
Sign(message []byte) ([]byte, error)
28+
}

common/localmsp/signer.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package localmsp
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/hyperledger/fabric/core/crypto/primitives"
23+
"github.com/hyperledger/fabric/common/crypto"
24+
cb "github.com/hyperledger/fabric/protos/common"
25+
"github.com/hyperledger/fabric/core/peer/msp"
26+
)
27+
28+
type mspSigner struct {
29+
}
30+
31+
// New returns a new instance of the msp-based LocalSigner.
32+
// It assumes that the local msp has been already initialized.
33+
// Look at mspmgmt.LoadLocalMsp for further information.
34+
func NewSigner() crypto.LocalSigner {
35+
return &mspSigner{}
36+
}
37+
38+
// NewSignatureHeader creates a SignatureHeader with the correct signing identity and a valid nonce
39+
func (s *mspSigner) NewSignatureHeader() (*cb.SignatureHeader, error) {
40+
signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
41+
if err != nil {
42+
return nil, fmt.Errorf("Failed getting MSP-based signer [%s]", err)
43+
}
44+
45+
creatorIdentityRaw, err := signer.Serialize()
46+
if err != nil {
47+
return nil, fmt.Errorf("Failed serializing creator public identity [%s]", err)
48+
}
49+
50+
nonce, err := primitives.GetRandomNonce()
51+
if err != nil {
52+
return nil, fmt.Errorf("Failed creating nonce [%s]", err)
53+
}
54+
55+
sh := &cb.SignatureHeader{}
56+
sh.Creator = creatorIdentityRaw
57+
sh.Nonce = nonce
58+
59+
return sh, nil
60+
}
61+
62+
// Sign a message which should embed a signature header created by NewSignatureHeader
63+
func (s *mspSigner) Sign(message []byte) ([]byte, error) {
64+
signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
65+
if err != nil {
66+
return nil, fmt.Errorf("Failed getting MSP-based signer [%s]", err)
67+
}
68+
69+
signature, err := signer.Sign(message)
70+
if err != nil {
71+
return nil, fmt.Errorf("Failed generating signature [%s]", err)
72+
}
73+
74+
return signature, nil
75+
}

common/localmsp/signer_test.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package localmsp
18+
19+
import (
20+
"os"
21+
"testing"
22+
23+
"github.com/hyperledger/fabric/core/crypto/primitives"
24+
"github.com/stretchr/testify/assert"
25+
"github.com/hyperledger/fabric/core/peer/msp"
26+
)
27+
28+
func TestMain(m *testing.M) {
29+
// 1. Determine MSP configuration
30+
var mspMgrConfigDir string
31+
var alternativeCfgPath = os.Getenv("ORDERER_CFG_PATH")
32+
if alternativeCfgPath != "" {
33+
mspMgrConfigDir = alternativeCfgPath + "/msp/sampleconfig/"
34+
} else if _, err := os.Stat("./msp/sampleconfig/"); err == nil {
35+
mspMgrConfigDir = "./msp/sampleconfig/"
36+
} else {
37+
mspMgrConfigDir = os.Getenv("GOPATH") + "/src/github.com/hyperledger/fabric/msp/sampleconfig/"
38+
}
39+
40+
if err := mspmgmt.LoadLocalMsp(mspMgrConfigDir); err != nil {
41+
os.Exit(-1)
42+
}
43+
44+
os.Exit(m.Run())
45+
}
46+
47+
func TestNewSigner(t *testing.T) {
48+
signer := NewSigner()
49+
assert.NotNil(t, signer, "Signer must be differentr from nil.")
50+
}
51+
52+
func TestMspSigner_NewSignatureHeader(t *testing.T) {
53+
signer := NewSigner()
54+
55+
sh, err := signer.NewSignatureHeader()
56+
if err != nil {
57+
t.Fatalf("Failed creting signature header [%s]", err)
58+
}
59+
60+
assert.NotNil(t, sh, "SignatureHeader must be different from nil")
61+
assert.Len(t, sh.Nonce, primitives.NonceSize, "SignatureHeader.Nonce must be of length %d", primitives.NonceSize)
62+
63+
mspIdentity, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
64+
assert.NoError(t, err, "Failed getting default MSP Identity")
65+
publicIdentity := mspIdentity.GetPublicVersion()
66+
assert.NotNil(t, publicIdentity, "Failed getting default public identity. It must be different from nil.")
67+
publicIdentityRaw, err := publicIdentity.Serialize()
68+
assert.NoError(t, err, "Failed serializing default public identity")
69+
assert.Equal(t, publicIdentityRaw, sh.Creator, "Creator must be local default signer identity")
70+
}
71+
72+
func TestMspSigner_Sign(t *testing.T) {
73+
signer := NewSigner()
74+
75+
msg := []byte("Hello World")
76+
sigma, err := signer.Sign(msg)
77+
assert.NoError(t, err, "FAiled generating signature")
78+
79+
// Verify signature
80+
mspIdentity, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
81+
assert.NoError(t, err, "Failed getting default MSP Identity")
82+
err = mspIdentity.Verify(msg, sigma)
83+
assert.NoError(t, err, "Failed verifiing signature")
84+
}

images/orderer/Dockerfile.in

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
FROM hyperledger/fabric-runtime:_TAG_
2-
ENV ORDERER_CFG_PATH /etc/hyperledger/fabric
3-
RUN mkdir -p /var/hyperledger/db /etc/hyperledger/fabric
2+
ENV ORDERER_CFG_PATH /etc/hyperledger/fabric/orderer
3+
RUN mkdir -p /var/hyperledger/db /etc/hyperledger/fabric/orderer
44
COPY payload/orderer /usr/local/bin
5-
COPY payload/orderer.yaml $ORDERER_CFG_PATH
5+
ADD payload/msp-sampleconfig.tar.bz2 $ORDERER_CFG_PATH/../
6+
COPY payload/orderer.yaml $ORDERER_CFG_PATH/
67
EXPOSE 7050
78
CMD orderer

orderer/localconfig/config.go

+23-11
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type General struct {
4848
GenesisFile string
4949
Profile Profile
5050
LogLevel string
51+
LocalMSPDir string
5152
}
5253

5354
// Genesis contains config which is used by the provisional bootstrapper
@@ -121,7 +122,8 @@ var defaults = TopLevel{
121122
Enabled: false,
122123
Address: "0.0.0.0:6060",
123124
},
124-
LogLevel: "INFO",
125+
LogLevel: "INFO",
126+
LocalMSPDir: "../msp/sampleconfig/",
125127
},
126128
RAMLedger: RAMLedger{
127129
HistorySize: 10000,
@@ -180,6 +182,12 @@ func (c *TopLevel) completeInitialization() {
180182
case c.General.Profile.Enabled && (c.General.Profile.Address == ""):
181183
logger.Infof("Profiling enabled and General.Profile.Address unset, setting to %s", defaults.General.Profile.Address)
182184
c.General.Profile.Address = defaults.General.Profile.Address
185+
case c.General.LocalMSPDir == "":
186+
logger.Infof("General.LocalMSPDir unset, setting to %s", defaults.General.LocalMSPDir)
187+
// Note, this is a bit of a weird one, the orderer may set the ORDERER_CFG_PATH after
188+
// the file is initialized, so we cannot initialize this in the structure, so we
189+
// deference the env portion here
190+
c.General.LocalMSPDir = filepath.Join(os.Getenv("ORDERER_CFG_PATH"), defaults.General.LocalMSPDir)
183191
case c.FileLedger.Prefix == "":
184192
logger.Infof("FileLedger.Prefix unset, setting to %s", defaults.FileLedger.Prefix)
185193
c.FileLedger.Prefix = defaults.FileLedger.Prefix
@@ -221,22 +229,26 @@ func Load() *TopLevel {
221229
config := viper.New()
222230

223231
config.SetConfigName("orderer")
224-
alternativeCfgPath := os.Getenv("ORDERER_CFG_PATH")
225-
if alternativeCfgPath != "" {
226-
logger.Infof("User defined config file path: %s", alternativeCfgPath)
227-
config.AddConfigPath(alternativeCfgPath) // Path to look for the config file in
228-
} else {
229-
config.AddConfigPath("./")
230-
config.AddConfigPath("../../.")
231-
config.AddConfigPath("../orderer/")
232-
config.AddConfigPath("../../orderer/")
232+
cfgPath := os.Getenv("ORDERER_CFG_PATH")
233+
if cfgPath == "" {
234+
logger.Infof("No orderer cfg path set, assuming development environment, deriving from go path")
233235
// Path to look for the config file in based on GOPATH
234236
gopath := os.Getenv("GOPATH")
235237
for _, p := range filepath.SplitList(gopath) {
236238
ordererPath := filepath.Join(p, "src/github.com/hyperledger/fabric/orderer/")
237-
config.AddConfigPath(ordererPath)
239+
if _, err := os.Stat(filepath.Join(ordererPath, "orderer.yaml")); err != nil {
240+
// The yaml file does not exist in this component of the go src
241+
continue
242+
}
243+
cfgPath = ordererPath
238244
}
245+
if cfgPath == "" {
246+
logger.Fatalf("Could not find orderer.yaml, try setting ORDERER_CFG_PATH or GOPATH correctly")
247+
}
248+
logger.Infof("Setting ORDERER_CFG_PATH to: %s", cfgPath)
249+
os.Setenv("ORDERER_CFG_PATH", cfgPath)
239250
}
251+
config.AddConfigPath(cfgPath) // Path to look for the config file in
240252

241253
// for environment variables
242254
config.SetEnvPrefix(Prefix)

orderer/main.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ import (
4040
"github.com/hyperledger/fabric/protos/utils"
4141

4242
"github.com/Shopify/sarama"
43+
"github.com/hyperledger/fabric/common/localmsp"
44+
"github.com/hyperledger/fabric/core/peer/msp"
4345
logging "github.com/op/go-logging"
4446
"google.golang.org/grpc"
4547
)
4648

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

4951
func main() {
52+
// Temporarilly set logging level until config is read
53+
logging.SetLevel(logging.INFO, "")
5054
conf := config.Load()
5155
flogging.InitFromSpec(conf.General.LogLevel)
5256

@@ -67,6 +71,12 @@ func main() {
6771
return
6872
}
6973

74+
// Load local MSP
75+
err = mspmgmt.LoadLocalMsp(conf.General.LocalMSPDir)
76+
if err != nil { // Handle errors reading the config file
77+
panic(fmt.Errorf("Failed initializing crypto [%s]", err))
78+
}
79+
7080
var lf ordererledger.Factory
7181
switch conf.General.LedgerType {
7282
case "file":
@@ -127,7 +137,7 @@ func main() {
127137
consenters["solo"] = solo.New()
128138
consenters["kafka"] = kafka.New(conf.Kafka.Version, conf.Kafka.Retry)
129139

130-
manager := multichain.NewManagerImpl(lf, consenters)
140+
manager := multichain.NewManagerImpl(lf, consenters, localmsp.NewSigner())
131141

132142
server := NewServer(
133143
manager,

orderer/mocks/multichain/multichain.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ func (mcs *ConsenterSupport) ChainID() string {
8585
}
8686

8787
// Sign returns the bytes passed in
88-
func (mcs *ConsenterSupport) Sign(message []byte) []byte {
89-
return message
88+
func (mcs *ConsenterSupport) Sign(message []byte) ([]byte, error) {
89+
return message, nil
9090
}
9191

9292
// NewSignatureHeader returns an empty signature header
93-
func (mcs *ConsenterSupport) NewSignatureHeader() *cb.SignatureHeader {
94-
return &cb.SignatureHeader{}
93+
func (mcs *ConsenterSupport) NewSignatureHeader() (*cb.SignatureHeader, error) {
94+
return &cb.SignatureHeader{}, nil
9595
}

0 commit comments

Comments
 (0)