Skip to content

Commit

Permalink
generation of verifying options based only on simulated config, fixes
Browse files Browse the repository at this point in the history
Signed-off-by: kopaygorodsky <vlad.kopaygorodsky@gmail.com>
  • Loading branch information
kopaygorodsky committed Oct 3, 2020
1 parent 229ddd5 commit 5ccc63f
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 193 deletions.
35 changes: 0 additions & 35 deletions integration/raft/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,41 +391,6 @@ var _ = Describe("EndToEnd reconfiguration and onboarding", func() {
By("Waiting for orderer3 to see the leader")
findLeader([]*ginkgomon.Runner{ordererRunners[2]})

By("Removing orderer3's TLS root CA certificate")
nwo.UpdateOrdererMSP(network, peer, orderer, "systemchannel", "OrdererOrg", func(config msp.FabricMSPConfig) msp.FabricMSPConfig {
config.TlsRootCerts = config.TlsRootCerts[:len(config.TlsRootCerts)-1]
return config
})

By("Killing orderer3")
o3Proc := ordererProcesses[2]
o3Proc.Signal(syscall.SIGKILL)
Eventually(o3Proc.Wait(), network.EventuallyTimeout).Should(Receive(MatchError("exit status 137")))

By("Restarting orderer3")
o3Runner := network.OrdererRunner(orderer3)
ordererRunners[2] = o3Runner
o3Proc = ifrit.Invoke(o3Runner)
Eventually(o3Proc.Ready(), network.EventuallyTimeout).Should(BeClosed())
ordererProcesses[2] = o3Proc

By("Ensuring TLS handshakes fail with the other orderers")
for i, oRunner := range ordererRunners {
if i < 2 {
Eventually(oRunner.Err(), network.EventuallyTimeout).Should(gbytes.Say("TLS handshake failed with error tls: failed to verify client certificate"))
continue
}
Eventually(oRunner.Err(), network.EventuallyTimeout).Should(gbytes.Say("TLS handshake failed with error remote error: tls: bad certificate"))
Eventually(oRunner.Err(), network.EventuallyTimeout).Should(gbytes.Say("Suspecting our own eviction from the channel"))
}

//we removed caCert a few steps before and now consensus metadata is invalid bacause orderer3's cert is signed by unknown authority.
By("Adding orderer3's TLS root CA certificate back after removal")
nwo.UpdateOrdererMSP(network, peer, orderer, "systemchannel", "OrdererOrg", func(config msp.FabricMSPConfig) msp.FabricMSPConfig {
config.TlsRootCerts = append(config.TlsRootCerts, caCert)
return config
})

By("Attemping to add a consenter with invalid certs")
// create new certs that are not in the channel config
ca, err := tlsgen.NewCA()
Expand Down
2 changes: 1 addition & 1 deletion orderer/consensus/etcdraft/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ func (c *Chain) ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig cha
return errors.Wrap(err, "failed to unmarshal new etcdraft metadata configuration")
}

verifyOpts, err := createX509VerifyOptions(oldOrdererConfig, newOrdererConfig)
verifyOpts, err := createX509VerifyOptions(newOrdererConfig)
if err != nil {
return errors.Wrapf(err, "failed to create x509 verify options from old and new orderer config")
}
Expand Down
2 changes: 1 addition & 1 deletion orderer/consensus/etcdraft/consenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func (c *Consenter) IsChannelMember(joinBlock *common.Block) (bool, error) {
return false, err
}

verifyOpts, err := createX509VerifyOptions(oc, nil)
verifyOpts, err := createX509VerifyOptions(oc)
if err != nil {
return false, errors.Wrapf(err, "failed to create x509 verify options from orderer config")
}
Expand Down
141 changes: 29 additions & 112 deletions orderer/consensus/etcdraft/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ SPDX-License-Identifier: Apache-2.0
package etcdraft

import (
"bytes"
"crypto/sha1"
"crypto/x509"
"encoding/pem"
"fmt"
"time"

"github.com/golang/protobuf/proto"
Expand Down Expand Up @@ -203,7 +200,7 @@ func ConsensusMetadataFromConfigBlock(block *common.Block) (*etcdraft.ConfigMeta
// VerifyConfigMetadata validates Raft config metadata.
// If x509.VerifyOpts is nil, it will do only sanity check of certificates.
// If ignoreCertExpiration is true, it will verify certificate and ignore expiration errors.
func VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts *x509.VerifyOptions, ignoreCertExpiration bool) error {
func VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts x509.VerifyOptions, ignoreCertExpiration bool) error {
if metadata == nil {
// defensive check. this should not happen as CheckConfigMetadata
// should always be called with non-nil config metadata
Expand Down Expand Up @@ -284,106 +281,30 @@ func parseCertificateListFromBytes(certs [][]byte) ([]*x509.Certificate, error)
return certificateList, nil
}

func getCertFingerprint(cert *x509.Certificate) (string, error) {
fingerprint := sha1.Sum(cert.Raw)
var buf bytes.Buffer
for i, f := range fingerprint {
if i > 0 {
if _, err := fmt.Fprintf(&buf, ":"); err != nil {
return "", errors.Wrapf(err, "building fingerprint of %s", cert.Raw)
}
}

if _, err := fmt.Fprintf(&buf, "%02X", f); err != nil {
return "", errors.Wrapf(err, "building fingerprint of %s", cert.Raw)
}
}

return buf.String(), nil
}

func createX509VerifyOptions(oldOrdererConfig, newOrdererConfig channelconfig.Orderer) (*x509.VerifyOptions, error) {
func createX509VerifyOptions(ordererConfig channelconfig.Orderer) (x509.VerifyOptions, error) {
tlsRoots := x509.NewCertPool()
tlsIntermediates := x509.NewCertPool()

tlsRootsMap := make(map[string]*x509.Certificate)
tlsIntermediatesMap := make(map[string]*x509.Certificate)

if oldOrdererConfig != nil {
for _, org := range oldOrdererConfig.Organizations() {
rootCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSRootCerts())
if err != nil {
return nil, errors.Wrap(err, "parsing tls root certs")
}
intermediateCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSIntermediateCerts())
if err != nil {
return nil, errors.Wrap(err, "parsing tls intermediate certs")
}

for _, cert := range rootCerts {
fingerprint, err := getCertFingerprint(cert)
if err != nil {
return nil, errors.WithStack(err)
}

if _, exists := tlsRootsMap[fingerprint]; !exists {
tlsRoots.AddCert(cert)
tlsRootsMap[fingerprint] = cert
}
}

for _, cert := range intermediateCerts {
fingerprint, err := getCertFingerprint(cert)
if err != nil {
return nil, errors.WithStack(err)
}

if _, exists := tlsIntermediatesMap[fingerprint]; !exists {
tlsIntermediates.AddCert(cert)
tlsIntermediatesMap[fingerprint] = cert
}
}
for _, org := range ordererConfig.Organizations() {
rootCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSRootCerts())
if err != nil {
return x509.VerifyOptions{}, errors.Wrap(err, "parsing tls root certs")
}
intermediateCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSIntermediateCerts())
if err != nil {
return x509.VerifyOptions{}, errors.Wrap(err, "parsing tls intermediate certs")
}
}

if newOrdererConfig != nil {
for _, org := range newOrdererConfig.Organizations() {
rootCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSRootCerts())
if err != nil {
return nil, errors.Wrap(err, "parsing tls root certs")
}
intermediateCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSIntermediateCerts())
if err != nil {
return nil, errors.Wrap(err, "parsing tls intermediate certs")
}

for _, cert := range rootCerts {
fingerprint, err := getCertFingerprint(cert)
if err != nil {
return nil, errors.WithStack(err)
}

if _, exists := tlsRootsMap[fingerprint]; !exists {
tlsRoots.AddCert(cert)
tlsRootsMap[fingerprint] = cert
}
}

for _, cert := range intermediateCerts {
fingerprint, err := getCertFingerprint(cert)
if err != nil {
return nil, errors.WithStack(err)
}
for _, cert := range rootCerts {
tlsRoots.AddCert(cert)
}

if _, exists := tlsIntermediatesMap[fingerprint]; !exists {
tlsIntermediates.AddCert(cert)
tlsIntermediatesMap[fingerprint] = cert
}
}
for _, cert := range intermediateCerts {
tlsIntermediates.AddCert(cert)
}
}

return &x509.VerifyOptions{
return x509.VerifyOptions{
Roots: tlsRoots,
Intermediates: tlsIntermediates,
KeyUsages: []x509.ExtKeyUsage{
Expand All @@ -393,8 +314,8 @@ func createX509VerifyOptions(oldOrdererConfig, newOrdererConfig channelconfig.Or
}, nil
}

//validateConsenterTLSCerts decodes PEM cert, parses and validates it. If opts is nil, then only sanity check is done.
func validateConsenterTLSCerts(c *etcdraft.Consenter, opts *x509.VerifyOptions, ignoreExpiration bool) error {
//validateConsenterTLSCerts decodes PEM cert, parses and validates it.
func validateConsenterTLSCerts(c *etcdraft.Consenter, opts x509.VerifyOptions, ignoreExpiration bool) error {
clientCert, err := parseCertificateFromBytes(c.ClientTlsCert)
if err != nil {
return errors.Wrapf(err, "parsing tls client cert of %s:%d", c.Host, c.Port)
Expand All @@ -405,24 +326,20 @@ func validateConsenterTLSCerts(c *etcdraft.Consenter, opts *x509.VerifyOptions,
return errors.Wrapf(err, "parsing tls server cert of %s:%d", c.Host, c.Port)
}

if opts != nil {
verifyOpts := *opts

var verify = func(certType string, cert *x509.Certificate, opts x509.VerifyOptions) error {
if _, err := clientCert.Verify(verifyOpts); err != nil {
if validationRes, ok := err.(x509.CertificateInvalidError); !ok || (!ignoreExpiration || validationRes.Reason != x509.Expired) {
return errors.Errorf("verifying tls %s cert with serial number %d: %v", certType, clientCert.SerialNumber, err)
}
var verify = func(certType string, cert *x509.Certificate, opts x509.VerifyOptions) error {
if _, err := clientCert.Verify(opts); err != nil {
if validationRes, ok := err.(x509.CertificateInvalidError); !ok || (!ignoreExpiration || validationRes.Reason != x509.Expired) {
return errors.Errorf("verifying tls %s cert with serial number %d: %v", certType, clientCert.SerialNumber, err)
}
return nil
}
return nil
}

if err := verify("client", clientCert, verifyOpts); err != nil {
return err
}
if err := verify("server", serverCert, verifyOpts); err != nil {
return err
}
if err := verify("client", clientCert, opts); err != nil {
return err
}
if err := verify("server", serverCert, opts); err != nil {
return err
}

return nil
Expand Down
12 changes: 6 additions & 6 deletions orderer/consensus/etcdraft/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestVerifyConfigMetadata(t *testing.T) {

rootCertPool := x509.NewCertPool()
rootCertPool.AddCert(caRootCert)
goodVerifyingOpts := &x509.VerifyOptions{
goodVerifyingOpts := x509.VerifyOptions{
Roots: rootCertPool,
KeyUsages: []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth,
Expand All @@ -182,7 +182,7 @@ func TestVerifyConfigMetadata(t *testing.T) {
for _, testCase := range []struct {
description string
metadata *etcdraftproto.ConfigMetadata
verifyOpts *x509.VerifyOptions
verifyOpts x509.VerifyOptions
errRegex string
}{
{
Expand Down Expand Up @@ -336,7 +336,7 @@ func TestVerifyConfigMetadata(t *testing.T) {
singleConsenter,
},
},
verifyOpts: &x509.VerifyOptions{},
verifyOpts: x509.VerifyOptions{},
errRegex: "certificate signed by unknown authority",
},
} {
Expand All @@ -354,7 +354,7 @@ func TestVerifyConfigMetadata(t *testing.T) {
tlsClientCert, err := ioutil.ReadFile(filepath.Join(ca1Dir, "client3.pem"))
require.Nil(t, err)

expiredCertVerifyOpts := *goodVerifyingOpts
expiredCertVerifyOpts := goodVerifyingOpts
expiredCertVerifyOpts.Roots.AddCert(tlsCaCert)
consenterWithExpiredCerts := &etcdraftproto.Consenter{
Host: "host1",
Expand All @@ -370,6 +370,6 @@ func TestVerifyConfigMetadata(t *testing.T) {
},
}

require.Nil(t, VerifyConfigMetadata(medatadaWithExpiredConsenter, &expiredCertVerifyOpts, true))
require.NotNil(t, VerifyConfigMetadata(medatadaWithExpiredConsenter, &expiredCertVerifyOpts, false))
require.Nil(t, VerifyConfigMetadata(medatadaWithExpiredConsenter, expiredCertVerifyOpts, true))
require.NotNil(t, VerifyConfigMetadata(medatadaWithExpiredConsenter, expiredCertVerifyOpts, false))
}
Loading

0 comments on commit 5ccc63f

Please sign in to comment.