From 1f49bfb0b9d0efb15c0b94a54b3cb1933a4c30f6 Mon Sep 17 00:00:00 2001 From: Gari Singh Date: Thu, 9 Mar 2017 09:04:03 -0500 Subject: [PATCH] [FAB-2714] Enable peer to start with TLS enabled https://jira.hyperledger.org/browse/FAB-2714 Prior to this change, the peer did not honor the TLS setting in core.yaml. With this change, the peer will now read the peer.tls.* settings to determine whether or not to start the main peer server with TLS enabled. This following changes were made: - core/comm/testdata/certs/generate.go - needed to add usage extension to be able to use server certs as client certs - core/peer/peer.go - added package scoped peerServer variable in order to support dynamic updates from config transactions - peer/node/start.go - loads TLS config and calls function in core/peer package in order to create the peer server The tests do include a test for mutual (client) TLS authentication, but this is not yet enabled for the peer on start up Change-Id: I9a6d19b928c36b7500d004a57b7d76e40bb18fd9 Signed-off-by: Gari Singh --- core/comm/testdata/certs/generate.go | 5 +- core/peer/peer.go | 21 +++ core/peer/pkg_test.go | 215 +++++++++++++++++++++++ core/peer/testdata/Org1-cert.pem | 13 ++ core/peer/testdata/Org1-key.pem | 5 + core/peer/testdata/Org1-server1-cert.pem | 13 ++ core/peer/testdata/Org1-server1-key.pem | 5 + core/peer/testdata/Org1-server2-cert.pem | 13 ++ core/peer/testdata/Org1-server2-key.pem | 5 + core/peer/testdata/Org2-cert.pem | 13 ++ core/peer/testdata/Org2-key.pem | 5 + core/peer/testdata/Org2-server1-cert.pem | 13 ++ core/peer/testdata/Org2-server1-key.pem | 5 + core/peer/testdata/Org2-server2-cert.pem | 13 ++ core/peer/testdata/Org2-server2-key.pem | 5 + core/peer/testdata/generate.go | 22 +++ peer/node/start.go | 49 +++++- 17 files changed, 412 insertions(+), 8 deletions(-) create mode 100644 core/peer/pkg_test.go create mode 100644 core/peer/testdata/Org1-cert.pem create mode 100644 core/peer/testdata/Org1-key.pem create mode 100644 core/peer/testdata/Org1-server1-cert.pem create mode 100644 core/peer/testdata/Org1-server1-key.pem create mode 100644 core/peer/testdata/Org1-server2-cert.pem create mode 100644 core/peer/testdata/Org1-server2-key.pem create mode 100644 core/peer/testdata/Org2-cert.pem create mode 100644 core/peer/testdata/Org2-key.pem create mode 100644 core/peer/testdata/Org2-server1-cert.pem create mode 100644 core/peer/testdata/Org2-server1-key.pem create mode 100644 core/peer/testdata/Org2-server2-cert.pem create mode 100644 core/peer/testdata/Org2-server2-key.pem create mode 100644 core/peer/testdata/generate.go diff --git a/core/comm/testdata/certs/generate.go b/core/comm/testdata/certs/generate.go index a03b2e713f8..86ab1fdcbff 100644 --- a/core/comm/testdata/certs/generate.go +++ b/core/comm/testdata/certs/generate.go @@ -128,7 +128,8 @@ func genServerCertificateECDSA(name string, signKey *ecdsa.PrivateKey, signCert return err } - template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} + template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth} //set the organization for the subject subject := subjectTemplate() @@ -262,7 +263,7 @@ func main() { } } //generate client certificates for the org - for k := 1; k <= *numServerCerts; k++ { + for k := 1; k <= *numClientCerts; k++ { err := genClientCertificateECDSA(fmt.Sprintf(baseOrgName+"%d-client%d", i, k), signKey, signCert) if err != nil { fmt.Printf("error generating client certificate for %s%d-client%d : %s\n", diff --git a/core/peer/peer.go b/core/peer/peer.go index 5fcbdd5ff29..0351470c20e 100644 --- a/core/peer/peer.go +++ b/core/peer/peer.go @@ -46,6 +46,8 @@ import ( var peerLogger = logging.MustGetLogger("peer") +var peerServer comm.GRPCServer + type chainSupport struct { configtxapi.Manager config.Application @@ -404,3 +406,22 @@ func (c *channelPolicyManagerGetter) Manager(channelID string) (policies.Manager policyManager := GetPolicyManager(channelID) return policyManager, policyManager != nil } + +// CreatePeerServer creates an instance of comm.GRPCServer +// This server is used for peer communications +func CreatePeerServer(listenAddress string, + secureConfig comm.SecureServerConfig) (comm.GRPCServer, error) { + + var err error + peerServer, err = comm.NewGRPCServer(listenAddress, secureConfig) + if err != nil { + peerLogger.Errorf("Failed to create peer server (%s)", err) + return nil, err + } + return peerServer, nil +} + +// GetPeerServer returns the peer server instance +func GetPeerServer() comm.GRPCServer { + return peerServer +} diff --git a/core/peer/pkg_test.go b/core/peer/pkg_test.go new file mode 100644 index 00000000000..a0cf4b174c6 --- /dev/null +++ b/core/peer/pkg_test.go @@ -0,0 +1,215 @@ +/* +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 peer_test + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "io/ioutil" + "path/filepath" + "testing" + "time" + + "google.golang.org/grpc/credentials" + + "golang.org/x/net/context" + "google.golang.org/grpc" + + "github.com/hyperledger/fabric/core/comm" + testpb "github.com/hyperledger/fabric/core/comm/testdata/grpc" + "github.com/hyperledger/fabric/core/peer" + "github.com/stretchr/testify/assert" +) + +// default timeout for grpc connections +var timeout = time.Second * 1 + +// test server to be registered with the GRPCServer +type testServiceServer struct{} + +func (tss *testServiceServer) EmptyCall(context.Context, *testpb.Empty) (*testpb.Empty, error) { + return new(testpb.Empty), nil +} + +// createCertPool creates an x509.CertPool from an array of PEM-encoded certificates +func createCertPool(rootCAs [][]byte) (*x509.CertPool, error) { + + certPool := x509.NewCertPool() + for _, rootCA := range rootCAs { + if !certPool.AppendCertsFromPEM(rootCA) { + return nil, errors.New("Failed to load root certificates") + } + } + return certPool, nil +} + +// helper function to invoke the EmptyCall againt the test service +func invokeEmptyCall(address string, dialOptions []grpc.DialOption) (*testpb.Empty, error) { + + //add DialOptions + dialOptions = append(dialOptions, grpc.WithBlock()) + dialOptions = append(dialOptions, grpc.WithTimeout(timeout)) + //create GRPC client conn + clientConn, err := grpc.Dial(address, dialOptions...) + if err != nil { + return nil, err + } + defer clientConn.Close() + + //create GRPC client + client := testpb.NewTestServiceClient(clientConn) + + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + //invoke service + empty, err := client.EmptyCall(ctx, new(testpb.Empty)) + if err != nil { + return nil, err + } + + return empty, nil +} + +func TestCreatePeerServer(t *testing.T) { + + t.Parallel() + + // load test certs from testdata + org1CA, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-cert.pem")) + org1Server1Key, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-server1-key.pem")) + org1Server1Cert, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-server1-cert.pem")) + org2CA, err := ioutil.ReadFile(filepath.Join("testdata", "Org2-cert.pem")) + org2Server1Key, err := ioutil.ReadFile(filepath.Join("testdata", "Org2-server1-key.pem")) + org2Server1Cert, err := ioutil.ReadFile(filepath.Join("testdata", "Org2-server1-cert.pem")) + + if err != nil { + t.Fatalf("Failed to load test certificates: %v", err) + } + + org1CertPool, err := createCertPool([][]byte{org1CA}) + org2CertPool, err := createCertPool([][]byte{org2CA}) + + if err != nil { + t.Fatalf("Failed to load root certificates into pool: %v", err) + } + + org1Creds := credentials.NewClientTLSFromCert(org1CertPool, "") + org2Creds := credentials.NewClientTLSFromCert(org2CertPool, "") + + // use server cert as client cert + org2ClientCert, err := tls.X509KeyPair(org2Server1Cert, org2Server1Key) + if err != nil { + t.Fatalf("Failed to load client certificate: %v", err) + } + org1Org2Creds := credentials.NewTLS(&tls.Config{ + Certificates: []tls.Certificate{org2ClientCert}, + RootCAs: org1CertPool, + }) + + // basic function tests + var tests = []struct { + name string + listenAddress string + secureConfig comm.SecureServerConfig + expectError bool + goodOptions []grpc.DialOption + badOptions []grpc.DialOption + }{ + { + name: "NoTLS", + listenAddress: fmt.Sprintf("localhost:%d", 4050), + secureConfig: comm.SecureServerConfig{ + UseTLS: false, + }, + expectError: false, + goodOptions: []grpc.DialOption{grpc.WithInsecure()}, + badOptions: []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)}, + }, + { + name: "BadAddress", + listenAddress: "badaddress", + secureConfig: comm.SecureServerConfig{ + UseTLS: false, + }, + expectError: true, + }, + { + name: "ServerTLSOrg1", + listenAddress: fmt.Sprintf("localhost:%d", 4051), + secureConfig: comm.SecureServerConfig{ + UseTLS: true, + ServerCertificate: org1Server1Cert, + ServerKey: org1Server1Key, + ServerRootCAs: [][]byte{org1CA}, + }, + expectError: false, + goodOptions: []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)}, + badOptions: []grpc.DialOption{grpc.WithTransportCredentials(org2Creds)}, + }, + { + name: "MutualTLSOrg1Org2", + listenAddress: fmt.Sprintf("localhost:%d", 4052), + secureConfig: comm.SecureServerConfig{ + UseTLS: true, + ServerCertificate: org1Server1Cert, + ServerKey: org1Server1Key, + ServerRootCAs: [][]byte{org1CA}, + ClientRootCAs: [][]byte{org1CA, org2CA}, + RequireClientCert: true, + }, + expectError: false, + goodOptions: []grpc.DialOption{grpc.WithTransportCredentials(org1Org2Creds)}, + badOptions: []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)}, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + t.Logf("Running test %s ...", test.name) + + _, err := peer.CreatePeerServer(test.listenAddress, test.secureConfig) + // check to see whether to not we expect an error + // we don't check the exact error because the comm package covers these cases + if test.expectError { + assert.Error(t, err, "CreatePeerServer should have returned an error") + } else { + assert.NoError(t, err, "CreatePeerServer should not have returned an error") + // get the server from peer + peerServer := peer.GetPeerServer() + assert.NotNil(t, peerServer, "GetPeerServer should not return a nil value") + // register a GRPC test service + testpb.RegisterTestServiceServer(peerServer.Server(), &testServiceServer{}) + go peerServer.Start() + defer peerServer.Stop() + + //invoke the EmptyCall service with good options + _, err = invokeEmptyCall(test.listenAddress, test.goodOptions) + assert.NoError(t, err, "Failed to invoke the EmptyCall service") + //invoke the EmptyCall service with bad options + _, err = invokeEmptyCall(test.listenAddress, test.badOptions) + assert.Error(t, err, "Expected error using bad dial options") + + } + }) + } +} diff --git a/core/peer/testdata/Org1-cert.pem b/core/peer/testdata/Org1-cert.pem new file mode 100644 index 00000000000..0d16cbd558e --- /dev/null +++ b/core/peer/testdata/Org1-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB4jCCAYigAwIBAgIQGm/MiEzhl9NQB7VQsWTwpzAKBggqhkjOPQQDAjBYMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy +YW5jaXNjbzENMAsGA1UEChMET3JnMTENMAsGA1UEAxMET3JnMTAeFw0xNzAzMDkx +MjE4NDBaFw0yNzAzMDcxMjE4NDBaMFgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD +YWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRPcmcx +MQ0wCwYDVQQDEwRPcmcxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEU70ukwCU +MIU7v7GTm2iQDPansRjHctQXiz3wLwTjnkxmCnvWG6DzkkOUTFrGQgC/BuUXnT+e +pVVYPHv3pyxXV6M0MDIwDgYDVR0PAQH/BAQDAgGmMA8GA1UdJQQIMAYGBFUdJQAw +DwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBAQXkEp2iDIrgjOg2U +Uc/NMTxHOapzr4c7a2//HrUN/QIhAP4C4dOzqw2WZSL5yaKGsDwVYXTzIX8VEzgH +S/iulKlP +-----END CERTIFICATE----- diff --git a/core/peer/testdata/Org1-key.pem b/core/peer/testdata/Org1-key.pem new file mode 100644 index 00000000000..0b18297cb1b --- /dev/null +++ b/core/peer/testdata/Org1-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPV6aiHMGDfHF6Ub+iKVcnDwyacwtZp5SMUnnMPWsYJtoAoGCCqGSM49 +AwEHoUQDQgAEU70ukwCUMIU7v7GTm2iQDPansRjHctQXiz3wLwTjnkxmCnvWG6Dz +kkOUTFrGQgC/BuUXnT+epVVYPHv3pyxXVw== +-----END EC PRIVATE KEY----- diff --git a/core/peer/testdata/Org1-server1-cert.pem b/core/peer/testdata/Org1-server1-cert.pem new file mode 100644 index 00000000000..66ab73d413e --- /dev/null +++ b/core/peer/testdata/Org1-server1-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB/DCCAaGgAwIBAgIRANHBGVHQ24Z7DyTeCJy0hkAwCgYIKoZIzj0EAwIwWDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG +cmFuY2lzY28xDTALBgNVBAoTBE9yZzExDTALBgNVBAMTBE9yZzEwHhcNMTcwMzA5 +MTIxODQwWhcNMjcwMzA3MTIxODQwWjBlMQswCQYDVQQGEwJVUzETMBEGA1UECBMK +Q2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMT3Jn +MS1zZXJ2ZXIxMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAAQK2y+RWueR/DA1azaTAOCWg2V5OQvaV/Z5w5eM0pnxFNigvL2M2587 +K9TyIko/q/FSugFcRlpwqluOfRNrS/pgoz8wPTAOBgNVHQ8BAf8EBAMCBaAwHQYD +VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCgYIKoZI +zj0EAwIDSQAwRgIhAOCcZX387r7wcIhGjugCa30FLfNt+JuzVmI1u6mQlyAhAiEA +hHaqckAlaGrf2RZ22JfuruIeBFspvynLo/R8wnWUgTU= +-----END CERTIFICATE----- diff --git a/core/peer/testdata/Org1-server1-key.pem b/core/peer/testdata/Org1-server1-key.pem new file mode 100644 index 00000000000..623c108c2dd --- /dev/null +++ b/core/peer/testdata/Org1-server1-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIFs7jdTFvAvefiEmo/l12AxECeajntSHWIEBWITL4TbloAoGCCqGSM49 +AwEHoUQDQgAECtsvkVrnkfwwNWs2kwDgloNleTkL2lf2ecOXjNKZ8RTYoLy9jNuf +OyvU8iJKP6vxUroBXEZacKpbjn0Ta0v6YA== +-----END EC PRIVATE KEY----- diff --git a/core/peer/testdata/Org1-server2-cert.pem b/core/peer/testdata/Org1-server2-cert.pem new file mode 100644 index 00000000000..c7e75343012 --- /dev/null +++ b/core/peer/testdata/Org1-server2-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+zCCAaCgAwIBAgIQUXz+3XMkFuny6scdi93EOTAKBggqhkjOPQQDAjBYMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy +YW5jaXNjbzENMAsGA1UEChMET3JnMTENMAsGA1UEAxMET3JnMTAeFw0xNzAzMDkx +MjE4NDBaFw0yNzAzMDcxMjE4NDBaMGUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD +YWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxPcmcx +LXNlcnZlcjIxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49 +AwEHA0IABOn36rJJ1NWZ6ghuzsx/KCtmY+yBHP6J/nDloqvUAGsPxtL/D0Wdn9c1 +pHeYBTkpqkpEuQiq2fxKCjH0rClh9YqjPzA9MA4GA1UdDwEB/wQEAwIFoDAdBgNV +HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAKBggqhkjO +PQQDAgNJADBGAiEAvtuTYx/9wVuuhDWl0P0PMmgSvpcWV1jIj2LT7xFdq/cCIQCp +s2LlnqyCJ1t6lBNpNbn/HYPYn46FQmvjhHGCzwW9kw== +-----END CERTIFICATE----- diff --git a/core/peer/testdata/Org1-server2-key.pem b/core/peer/testdata/Org1-server2-key.pem new file mode 100644 index 00000000000..a10ff9137a3 --- /dev/null +++ b/core/peer/testdata/Org1-server2-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIKWbEerXeYWnExsy0baJPL8RChzY/7JVz0QQbs0efZjnoAoGCCqGSM49 +AwEHoUQDQgAE6ffqsknU1ZnqCG7OzH8oK2Zj7IEc/on+cOWiq9QAaw/G0v8PRZ2f +1zWkd5gFOSmqSkS5CKrZ/EoKMfSsKWH1ig== +-----END EC PRIVATE KEY----- diff --git a/core/peer/testdata/Org2-cert.pem b/core/peer/testdata/Org2-cert.pem new file mode 100644 index 00000000000..e8f1b4b3a71 --- /dev/null +++ b/core/peer/testdata/Org2-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB4zCCAYigAwIBAgIQctpUUW4DlMMhPEDnOcZBsDAKBggqhkjOPQQDAjBYMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy +YW5jaXNjbzENMAsGA1UEChMET3JnMjENMAsGA1UEAxMET3JnMjAeFw0xNzAzMDkx +MjE4NDBaFw0yNzAzMDcxMjE4NDBaMFgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD +YWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRPcmcy +MQ0wCwYDVQQDEwRPcmcyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4t3xokqU +oq6M+cneFK5r/MLT/vAYFfu/67AGYWaFJKN7xPzlREO1VbGqz6AvNSBJsq1+k8Mq +uw8YtJyQnfghD6M0MDIwDgYDVR0PAQH/BAQDAgGmMA8GA1UdJQQIMAYGBFUdJQAw +DwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEAoTYAwlEu2g/fvwmb +v6wgVs6lAN0nDfttySDZqfJdOJ8CIQCcYOqoXVxPvHS5re4UhcBU+pu+7rRYuH6t +37f6tMOgKQ== +-----END CERTIFICATE----- diff --git a/core/peer/testdata/Org2-key.pem b/core/peer/testdata/Org2-key.pem new file mode 100644 index 00000000000..b0b44d921cb --- /dev/null +++ b/core/peer/testdata/Org2-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDNhajAyPe7+ofYFs/9ZYtOsHSoYC6FWtNiF3VaDWkILoAoGCCqGSM49 +AwEHoUQDQgAE4t3xokqUoq6M+cneFK5r/MLT/vAYFfu/67AGYWaFJKN7xPzlREO1 +VbGqz6AvNSBJsq1+k8Mquw8YtJyQnfghDw== +-----END EC PRIVATE KEY----- diff --git a/core/peer/testdata/Org2-server1-cert.pem b/core/peer/testdata/Org2-server1-cert.pem new file mode 100644 index 00000000000..d5fde7853a5 --- /dev/null +++ b/core/peer/testdata/Org2-server1-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+zCCAaCgAwIBAgIQUZ/QyyHUYl4zIuKxdxcHCTAKBggqhkjOPQQDAjBYMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy +YW5jaXNjbzENMAsGA1UEChMET3JnMjENMAsGA1UEAxMET3JnMjAeFw0xNzAzMDkx +MjE4NDBaFw0yNzAzMDcxMjE4NDBaMGUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD +YWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxPcmcy +LXNlcnZlcjExEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49 +AwEHA0IABPGTbJUzh8uE81pbJfd3cO0MU94I87IPLQwe1weEC3aCcZ+awF4kIT5T +Z/SmTiDGHf1BH3CONUaTGYXKtioL2mqjPzA9MA4GA1UdDwEB/wQEAwIFoDAdBgNV +HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAKBggqhkjO +PQQDAgNJADBGAiEAjJ9iEz1dix1j+t+TMJtDLsLwFpnmcRUsrTlUfh1Fzg0CIQCx +K5rXgKTR48yMQ1mTizTNljd3I+DsNGWPDrbKHgIg+g== +-----END CERTIFICATE----- diff --git a/core/peer/testdata/Org2-server1-key.pem b/core/peer/testdata/Org2-server1-key.pem new file mode 100644 index 00000000000..18914f7e129 --- /dev/null +++ b/core/peer/testdata/Org2-server1-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIJZHiy1JhS/mosbf1VGOuus63/XsG2rBug79RmUOlcU5oAoGCCqGSM49 +AwEHoUQDQgAE8ZNslTOHy4TzWlsl93dw7QxT3gjzsg8tDB7XB4QLdoJxn5rAXiQh +PlNn9KZOIMYd/UEfcI41RpMZhcq2Kgvaag== +-----END EC PRIVATE KEY----- diff --git a/core/peer/testdata/Org2-server2-cert.pem b/core/peer/testdata/Org2-server2-cert.pem new file mode 100644 index 00000000000..986fc33ace9 --- /dev/null +++ b/core/peer/testdata/Org2-server2-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB+zCCAaGgAwIBAgIRALSYDDlVt7w7Fw7cdP8F9LMwCgYIKoZIzj0EAwIwWDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG +cmFuY2lzY28xDTALBgNVBAoTBE9yZzIxDTALBgNVBAMTBE9yZzIwHhcNMTcwMzA5 +MTIxODQwWhcNMjcwMzA3MTIxODQwWjBlMQswCQYDVQQGEwJVUzETMBEGA1UECBMK +Q2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMT3Jn +Mi1zZXJ2ZXIyMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAAQttx8Y8K31yCxoHX+iQLF7fu0ZU2EHtkAaD9T69emDiWLA5qCpksjr +0IwoLvJymwa2OR+2rrMzqI65+CvZNT4koz8wPTAOBgNVHQ8BAf8EBAMCBaAwHQYD +VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCgYIKoZI +zj0EAwIDSAAwRQIgeciUm1lmT+nOawKmgEBeiP53VczMtT7S5MHZOCBgroUCIQCN +8RSB44VgUwjfZfdW9Kr5xB5R6ufzAkGC6xlPbqiYPQ== +-----END CERTIFICATE----- diff --git a/core/peer/testdata/Org2-server2-key.pem b/core/peer/testdata/Org2-server2-key.pem new file mode 100644 index 00000000000..0f674d27cc7 --- /dev/null +++ b/core/peer/testdata/Org2-server2-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIBn9Ftx1gfZXp8bCP2yOHv2y7fX1vlIluXavEl4RQqYIoAoGCCqGSM49 +AwEHoUQDQgAELbcfGPCt9cgsaB1/okCxe37tGVNhB7ZAGg/U+vXpg4liwOagqZLI +69CMKC7ycpsGtjkftq6zM6iOufgr2TU+JA== +-----END EC PRIVATE KEY----- diff --git a/core/peer/testdata/generate.go b/core/peer/testdata/generate.go new file mode 100644 index 00000000000..3553896a7c6 --- /dev/null +++ b/core/peer/testdata/generate.go @@ -0,0 +1,22 @@ +/* +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. +*/ + +// +build ignore + +//go:generate -command gencerts go run $GOPATH/src/github.com/hyperledger/fabric/core/comm/testdata/certs/generate.go +//go:generate gencerts -orgs 2 -child-orgs 0 -servers 2 -clients 0 + +package testdata diff --git a/peer/node/start.go b/peer/node/start.go index ae1c2325dcb..79466bc30a0 100644 --- a/peer/node/start.go +++ b/peer/node/start.go @@ -18,6 +18,7 @@ package node import ( "fmt" + "io/ioutil" "net" "net/http" "os" @@ -87,6 +88,35 @@ func initSysCCs() { logger.Infof("Deployed system chaincodess") } +// load the TLS config for the server(s) +func loadTLSConfig() comm.SecureServerConfig { + + secureConfig := comm.SecureServerConfig{ + UseTLS: viper.GetBool("peer.tls.enabled"), + } + + if secureConfig.UseTLS { + // get the certs from the file system + serverKey, err := ioutil.ReadFile(viper.GetString("peer.tls.key.file")) + serverCert, err := ioutil.ReadFile(viper.GetString("peer.tls.cert.file")) + // must have both key and cert file + if err != nil { + logger.Fatalf("Error loading TLS key and/or certificate (%s)", err) + } + secureConfig.ServerCertificate = serverCert + secureConfig.ServerKey = serverKey + // check for root cert + if viper.GetString("peer.tls.rootcert.file") != "" { + rootCert, err := ioutil.ReadFile(viper.GetString("peer.tls.rootcert.file")) + if err != nil { + logger.Fatalf("Error loading TLS root certificate (%s)", err) + } + secureConfig.ServerRootCAs = [][]byte{rootCert} + } + } + return secureConfig +} + func serve(args []string) error { ledgermgmt.Initialize() // Parameter overrides must be processed before any paramaters are @@ -111,6 +141,7 @@ func serve(args []string) error { listenAddr := viper.GetString("peer.listenAddress") + /** TODO remove if "" == listenAddr { logger.Debug("Listen address not specified, using peer endpoint address") listenAddr = peerEndpoint.Address @@ -132,6 +163,12 @@ func serve(args []string) error { fmt.Println("Failed to return new GRPC server: ", err) return err } + */ + secureConfig := loadTLSConfig() + peerServer, err := peer.CreatePeerServer(listenAddr, secureConfig) + if err != nil { + logger.Fatalf("Failed to create peer server (%s)", err) + } //TODO - do we need different SSL material for events ? ehubGrpcServer, err := createEventHubServer(secureConfig) @@ -139,16 +176,16 @@ func serve(args []string) error { grpclog.Fatalf("Failed to create ehub server: %v", err) } - registerChaincodeSupport(grpcServer.Server()) + registerChaincodeSupport(peerServer.Server()) logger.Debugf("Running peer") // Register the Admin server - pb.RegisterAdminServer(grpcServer.Server(), core.NewAdminServer()) + pb.RegisterAdminServer(peerServer.Server(), core.NewAdminServer()) // Register the Endorser server serverEndorser := endorser.NewEndorserServer() - pb.RegisterEndorserServer(grpcServer.Server(), serverEndorser) + pb.RegisterEndorserServer(peerServer.Server(), serverEndorser) // Initialize gossip component bootstrap := viper.GetStringSlice("peer.gossip.bootstrap") @@ -162,7 +199,7 @@ func serve(args []string) error { peer.NewChannelPolicyManagerGetter(), localmsp.NewSigner(), mgmt.NewDeserializersManager()) - service.InitGossipService(serializedIdentity, peerEndpoint.Address, grpcServer.Server(), messageCryptoService, bootstrap...) + service.InitGossipService(serializedIdentity, peerEndpoint.Address, peerServer.Server(), messageCryptoService, bootstrap...) defer service.GetGossipService().Stop() //initialize system chaincodes @@ -233,10 +270,10 @@ func serve(args []string) error { go func() { var grpcErr error - if grpcErr = grpcServer.Start(); grpcErr != nil { + if grpcErr = peerServer.Start(); grpcErr != nil { grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr) } else { - logger.Info("grpc server exited") + logger.Info("peer server exited") } serve <- grpcErr }()