github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/consensus/etcdraft/util.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package etcdraft
     8  
     9  import (
    10  	"crypto/x509"
    11  	"encoding/pem"
    12  	"time"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	"github.com/hechain20/hechain/bccsp"
    16  	"github.com/hechain20/hechain/common/channelconfig"
    17  	"github.com/hechain20/hechain/common/configtx"
    18  	"github.com/hechain20/hechain/common/crypto"
    19  	"github.com/hechain20/hechain/common/flogging"
    20  	"github.com/hechain20/hechain/orderer/common/cluster"
    21  	"github.com/hechain20/hechain/protoutil"
    22  	"github.com/hyperledger/fabric-protos-go/common"
    23  	"github.com/hyperledger/fabric-protos-go/orderer"
    24  	"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    25  	"github.com/pkg/errors"
    26  	"go.etcd.io/etcd/raft"
    27  	"go.etcd.io/etcd/raft/raftpb"
    28  )
    29  
    30  // RaftPeers maps consenters to slice of raft.Peer
    31  func RaftPeers(consenterIDs []uint64) []raft.Peer {
    32  	var peers []raft.Peer
    33  
    34  	for _, raftID := range consenterIDs {
    35  		peers = append(peers, raft.Peer{ID: raftID})
    36  	}
    37  	return peers
    38  }
    39  
    40  type ConsentersMap map[string]struct{}
    41  
    42  func (c ConsentersMap) Exists(consenter *etcdraft.Consenter) bool {
    43  	_, exists := c[string(consenter.ClientTlsCert)]
    44  	return exists
    45  }
    46  
    47  // ConsentersToMap maps consenters into set where key is client TLS certificate
    48  func ConsentersToMap(consenters []*etcdraft.Consenter) ConsentersMap {
    49  	set := map[string]struct{}{}
    50  	for _, c := range consenters {
    51  		set[string(c.ClientTlsCert)] = struct{}{}
    52  	}
    53  	return set
    54  }
    55  
    56  // MetadataHasDuplication returns an error if the metadata has duplication of consenters.
    57  // A duplication is defined by having a server or a client TLS certificate that is found
    58  // in two different consenters, regardless of the type of certificate (client/server).
    59  func MetadataHasDuplication(md *etcdraft.ConfigMetadata) error {
    60  	if md == nil {
    61  		return errors.New("nil metadata")
    62  	}
    63  
    64  	for _, consenter := range md.Consenters {
    65  		if consenter == nil {
    66  			return errors.New("nil consenter in metadata")
    67  		}
    68  	}
    69  
    70  	seen := make(map[string]struct{})
    71  	for _, consenter := range md.Consenters {
    72  		serverKey := string(consenter.ServerTlsCert)
    73  		clientKey := string(consenter.ClientTlsCert)
    74  		_, duplicateServerCert := seen[serverKey]
    75  		_, duplicateClientCert := seen[clientKey]
    76  		if duplicateServerCert || duplicateClientCert {
    77  			return errors.Errorf("duplicate consenter: server cert: %s, client cert: %s", serverKey, clientKey)
    78  		}
    79  
    80  		seen[serverKey] = struct{}{}
    81  		seen[clientKey] = struct{}{}
    82  	}
    83  	return nil
    84  }
    85  
    86  // MetadataFromConfigValue reads and translates configuration updates from config value into raft metadata
    87  func MetadataFromConfigValue(configValue *common.ConfigValue) (*etcdraft.ConfigMetadata, error) {
    88  	consensusTypeValue := &orderer.ConsensusType{}
    89  	if err := proto.Unmarshal(configValue.Value, consensusTypeValue); err != nil {
    90  		return nil, errors.Wrap(err, "failed to unmarshal consensusType config update")
    91  	}
    92  
    93  	updatedMetadata := &etcdraft.ConfigMetadata{}
    94  	if err := proto.Unmarshal(consensusTypeValue.Metadata, updatedMetadata); err != nil {
    95  		return nil, errors.Wrap(err, "failed to unmarshal updated (new) etcdraft metadata configuration")
    96  	}
    97  
    98  	return updatedMetadata, nil
    99  }
   100  
   101  // MetadataFromConfigUpdate extracts consensus metadata from config update
   102  func MetadataFromConfigUpdate(update *common.ConfigUpdate) (*etcdraft.ConfigMetadata, error) {
   103  	var baseVersion uint64
   104  	if update.ReadSet != nil && update.ReadSet.Groups != nil {
   105  		if ordererConfigGroup, ok := update.ReadSet.Groups["Orderer"]; ok {
   106  			if val, ok := ordererConfigGroup.Values["ConsensusType"]; ok {
   107  				baseVersion = val.Version
   108  			}
   109  		}
   110  	}
   111  
   112  	if update.WriteSet != nil && update.WriteSet.Groups != nil {
   113  		if ordererConfigGroup, ok := update.WriteSet.Groups["Orderer"]; ok {
   114  			if val, ok := ordererConfigGroup.Values["ConsensusType"]; ok {
   115  				if baseVersion == val.Version {
   116  					// Only if the version in the write set differs from the read-set
   117  					// should we consider this to be an update to the consensus type
   118  					return nil, nil
   119  				}
   120  				return MetadataFromConfigValue(val)
   121  			}
   122  		}
   123  	}
   124  	return nil, nil
   125  }
   126  
   127  // ConfigChannelHeader expects a config block and returns the header type
   128  // of the config envelope wrapped in it, e.g. HeaderType_ORDERER_TRANSACTION
   129  func ConfigChannelHeader(block *common.Block) (hdr *common.ChannelHeader, err error) {
   130  	envelope, err := protoutil.ExtractEnvelope(block, 0)
   131  	if err != nil {
   132  		return nil, errors.Wrap(err, "failed to extract envelope from the block")
   133  	}
   134  
   135  	channelHeader, err := protoutil.ChannelHeader(envelope)
   136  	if err != nil {
   137  		return nil, errors.Wrap(err, "cannot extract channel header")
   138  	}
   139  
   140  	return channelHeader, nil
   141  }
   142  
   143  // ConfigEnvelopeFromBlock extracts configuration envelope from the block based on the
   144  // config type, i.e. HeaderType_ORDERER_TRANSACTION or HeaderType_CONFIG
   145  func ConfigEnvelopeFromBlock(block *common.Block) (*common.Envelope, error) {
   146  	if block == nil {
   147  		return nil, errors.New("nil block")
   148  	}
   149  
   150  	envelope, err := protoutil.ExtractEnvelope(block, 0)
   151  	if err != nil {
   152  		return nil, errors.Wrapf(err, "failed to extract envelope from the block")
   153  	}
   154  
   155  	channelHeader, err := protoutil.ChannelHeader(envelope)
   156  	if err != nil {
   157  		return nil, errors.Wrap(err, "cannot extract channel header")
   158  	}
   159  
   160  	switch channelHeader.Type {
   161  	case int32(common.HeaderType_ORDERER_TRANSACTION):
   162  		payload, err := protoutil.UnmarshalPayload(envelope.Payload)
   163  		if err != nil {
   164  			return nil, errors.Wrap(err, "failed to unmarshal envelope to extract config payload for orderer transaction")
   165  		}
   166  		configEnvelop, err := protoutil.UnmarshalEnvelope(payload.Data)
   167  		if err != nil {
   168  			return nil, errors.Wrap(err, "failed to unmarshal config envelope for orderer type transaction")
   169  		}
   170  
   171  		return configEnvelop, nil
   172  	case int32(common.HeaderType_CONFIG):
   173  		return envelope, nil
   174  	default:
   175  		return nil, errors.Errorf("unexpected header type: %v", channelHeader.Type)
   176  	}
   177  }
   178  
   179  // ConsensusMetadataFromConfigBlock reads consensus metadata updates from the configuration block
   180  func ConsensusMetadataFromConfigBlock(block *common.Block) (*etcdraft.ConfigMetadata, error) {
   181  	if block == nil {
   182  		return nil, errors.New("nil block")
   183  	}
   184  
   185  	if !protoutil.IsConfigBlock(block) {
   186  		return nil, errors.New("not a config block")
   187  	}
   188  
   189  	configEnvelope, err := ConfigEnvelopeFromBlock(block)
   190  	if err != nil {
   191  		return nil, errors.Wrap(err, "cannot read config update")
   192  	}
   193  
   194  	payload, err := protoutil.UnmarshalPayload(configEnvelope.Payload)
   195  	if err != nil {
   196  		return nil, errors.Wrap(err, "failed to extract payload from config envelope")
   197  	}
   198  	// get config update
   199  	configUpdate, err := configtx.UnmarshalConfigUpdateFromPayload(payload)
   200  	if err != nil {
   201  		return nil, errors.Wrap(err, "could not read config update")
   202  	}
   203  
   204  	return MetadataFromConfigUpdate(configUpdate)
   205  }
   206  
   207  // VerifyConfigMetadata validates Raft config metadata.
   208  // Note: ignores certificates expiration.
   209  func VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts x509.VerifyOptions) error {
   210  	if metadata == nil {
   211  		// defensive check. this should not happen as CheckConfigMetadata
   212  		// should always be called with non-nil config metadata
   213  		return errors.Errorf("nil Raft config metadata")
   214  	}
   215  
   216  	if metadata.Options == nil {
   217  		return errors.Errorf("nil Raft config metadata options")
   218  	}
   219  
   220  	if metadata.Options.HeartbeatTick == 0 ||
   221  		metadata.Options.ElectionTick == 0 ||
   222  		metadata.Options.MaxInflightBlocks == 0 {
   223  		// if SnapshotIntervalSize is zero, DefaultSnapshotIntervalSize is used
   224  		return errors.Errorf("none of HeartbeatTick (%d), ElectionTick (%d) and MaxInflightBlocks (%d) can be zero",
   225  			metadata.Options.HeartbeatTick, metadata.Options.ElectionTick, metadata.Options.MaxInflightBlocks)
   226  	}
   227  
   228  	// check Raft options
   229  	if metadata.Options.ElectionTick <= metadata.Options.HeartbeatTick {
   230  		return errors.Errorf("ElectionTick (%d) must be greater than HeartbeatTick (%d)",
   231  			metadata.Options.ElectionTick, metadata.Options.HeartbeatTick)
   232  	}
   233  
   234  	if d, err := time.ParseDuration(metadata.Options.TickInterval); err != nil {
   235  		return errors.Errorf("failed to parse TickInterval (%s) to time duration: %s", metadata.Options.TickInterval, err)
   236  	} else if d == 0 {
   237  		return errors.Errorf("TickInterval cannot be zero")
   238  	}
   239  
   240  	if len(metadata.Consenters) == 0 {
   241  		return errors.Errorf("empty consenter set")
   242  	}
   243  
   244  	// verifying certificates for being signed by CA, expiration is ignored
   245  	for _, consenter := range metadata.Consenters {
   246  		if consenter == nil {
   247  			return errors.Errorf("metadata has nil consenter")
   248  		}
   249  		if err := validateConsenterTLSCerts(consenter, verifyOpts, true); err != nil {
   250  			return errors.WithMessagef(err, "consenter %s:%d has invalid certificate", consenter.Host, consenter.Port)
   251  		}
   252  	}
   253  
   254  	if err := MetadataHasDuplication(metadata); err != nil {
   255  		return err
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  func parseCertificateFromBytes(cert []byte) (*x509.Certificate, error) {
   262  	pemBlock, _ := pem.Decode(cert)
   263  	if pemBlock == nil {
   264  		return &x509.Certificate{}, errors.Errorf("no PEM data found in cert[% x]", cert)
   265  	}
   266  
   267  	certificate, err := x509.ParseCertificate(pemBlock.Bytes)
   268  	if err != nil {
   269  		return nil, errors.Errorf("%s TLS certificate has invalid ASN1 structure %s", err, string(pemBlock.Bytes))
   270  	}
   271  
   272  	return certificate, nil
   273  }
   274  
   275  func parseCertificateListFromBytes(certs [][]byte) ([]*x509.Certificate, error) {
   276  	var certificateList []*x509.Certificate
   277  
   278  	for _, cert := range certs {
   279  		certificate, err := parseCertificateFromBytes(cert)
   280  		if err != nil {
   281  			return certificateList, err
   282  		}
   283  
   284  		certificateList = append(certificateList, certificate)
   285  	}
   286  
   287  	return certificateList, nil
   288  }
   289  
   290  func createX509VerifyOptions(ordererConfig channelconfig.Orderer) (x509.VerifyOptions, error) {
   291  	tlsRoots := x509.NewCertPool()
   292  	tlsIntermediates := x509.NewCertPool()
   293  
   294  	for _, org := range ordererConfig.Organizations() {
   295  		rootCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSRootCerts())
   296  		if err != nil {
   297  			return x509.VerifyOptions{}, errors.Wrap(err, "parsing tls root certs")
   298  		}
   299  		intermediateCerts, err := parseCertificateListFromBytes(org.MSP().GetTLSIntermediateCerts())
   300  		if err != nil {
   301  			return x509.VerifyOptions{}, errors.Wrap(err, "parsing tls intermediate certs")
   302  		}
   303  
   304  		for _, cert := range rootCerts {
   305  			tlsRoots.AddCert(cert)
   306  		}
   307  
   308  		for _, cert := range intermediateCerts {
   309  			tlsIntermediates.AddCert(cert)
   310  		}
   311  	}
   312  
   313  	return x509.VerifyOptions{
   314  		Roots:         tlsRoots,
   315  		Intermediates: tlsIntermediates,
   316  		KeyUsages: []x509.ExtKeyUsage{
   317  			x509.ExtKeyUsageClientAuth,
   318  			x509.ExtKeyUsageServerAuth,
   319  		},
   320  	}, nil
   321  }
   322  
   323  // validateConsenterTLSCerts decodes PEM cert, parses and validates it.
   324  func validateConsenterTLSCerts(c *etcdraft.Consenter, opts x509.VerifyOptions, ignoreExpiration bool) error {
   325  	clientCert, err := parseCertificateFromBytes(c.ClientTlsCert)
   326  	if err != nil {
   327  		return errors.Wrapf(err, "parsing tls client cert of %s:%d", c.Host, c.Port)
   328  	}
   329  
   330  	serverCert, err := parseCertificateFromBytes(c.ServerTlsCert)
   331  	if err != nil {
   332  		return errors.Wrapf(err, "parsing tls server cert of %s:%d", c.Host, c.Port)
   333  	}
   334  
   335  	verify := func(certType string, cert *x509.Certificate, opts x509.VerifyOptions) error {
   336  		if _, err := cert.Verify(opts); err != nil {
   337  			if validationRes, ok := err.(x509.CertificateInvalidError); !ok || (!ignoreExpiration || validationRes.Reason != x509.Expired) {
   338  				return errors.Wrapf(err, "verifying tls %s cert with serial number %d", certType, cert.SerialNumber)
   339  			}
   340  		}
   341  		return nil
   342  	}
   343  
   344  	if err := verify("client", clientCert, opts); err != nil {
   345  		return err
   346  	}
   347  	if err := verify("server", serverCert, opts); err != nil {
   348  		return err
   349  	}
   350  
   351  	return nil
   352  }
   353  
   354  // ConsenterCertificate denotes a TLS certificate of a consenter
   355  type ConsenterCertificate struct {
   356  	ConsenterCertificate []byte
   357  	CryptoProvider       bccsp.BCCSP
   358  	Logger               *flogging.FabricLogger
   359  }
   360  
   361  // IsConsenterOfChannel returns whether the caller is a consenter of a channel
   362  // by inspecting the given configuration block.
   363  // It returns nil if true, else returns an error.
   364  func (conCert ConsenterCertificate) IsConsenterOfChannel(configBlock *common.Block) error {
   365  	if configBlock == nil || configBlock.Header == nil {
   366  		return errors.New("nil block or nil header")
   367  	}
   368  	envelopeConfig, err := protoutil.ExtractEnvelope(configBlock, 0)
   369  	if err != nil {
   370  		return err
   371  	}
   372  	bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, conCert.CryptoProvider)
   373  	if err != nil {
   374  		return err
   375  	}
   376  	oc, exists := bundle.OrdererConfig()
   377  	if !exists {
   378  		return errors.New("no orderer config in bundle")
   379  	}
   380  	m := &etcdraft.ConfigMetadata{}
   381  	if err := proto.Unmarshal(oc.ConsensusMetadata(), m); err != nil {
   382  		return err
   383  	}
   384  
   385  	bl, _ := pem.Decode(conCert.ConsenterCertificate)
   386  	if bl == nil {
   387  		return errors.Errorf("my consenter certificate %s is not a valid PEM", string(conCert.ConsenterCertificate))
   388  	}
   389  
   390  	myCertDER := bl.Bytes
   391  
   392  	var failedMatches []string
   393  	for _, consenter := range m.Consenters {
   394  		candidateBlock, _ := pem.Decode(consenter.ServerTlsCert)
   395  		if candidateBlock == nil {
   396  			return errors.Errorf("candidate server certificate %s is not a valid PEM", string(consenter.ServerTlsCert))
   397  		}
   398  		sameServerCertErr := crypto.CertificatesWithSamePublicKey(myCertDER, candidateBlock.Bytes)
   399  
   400  		candidateBlock, _ = pem.Decode(consenter.ClientTlsCert)
   401  		if candidateBlock == nil {
   402  			return errors.Errorf("candidate client certificate %s is not a valid PEM", string(consenter.ClientTlsCert))
   403  		}
   404  		sameClientCertErr := crypto.CertificatesWithSamePublicKey(myCertDER, candidateBlock.Bytes)
   405  
   406  		if sameServerCertErr == nil || sameClientCertErr == nil {
   407  			return nil
   408  		}
   409  		conCert.Logger.Debugf("I am not %s:%d because %s, %s", consenter.Host, consenter.Port, sameServerCertErr, sameClientCertErr)
   410  		failedMatches = append(failedMatches, string(consenter.ClientTlsCert))
   411  	}
   412  	conCert.Logger.Debugf("Failed matching our certificate %s against certificates encoded in config block %d: %v",
   413  		string(conCert.ConsenterCertificate),
   414  		configBlock.Header.Number,
   415  		failedMatches)
   416  
   417  	return cluster.ErrNotInChannel
   418  }
   419  
   420  // NodeExists returns trues if node id exists in the slice
   421  // and false otherwise
   422  func NodeExists(id uint64, nodes []uint64) bool {
   423  	for _, nodeID := range nodes {
   424  		if nodeID == id {
   425  			return true
   426  		}
   427  	}
   428  	return false
   429  }
   430  
   431  // ConfChange computes Raft configuration changes based on current Raft
   432  // configuration state and consenters IDs stored in RaftMetadata.
   433  func ConfChange(blockMetadata *etcdraft.BlockMetadata, confState *raftpb.ConfState) *raftpb.ConfChange {
   434  	raftConfChange := &raftpb.ConfChange{}
   435  
   436  	// need to compute conf changes to propose
   437  	if len(confState.Nodes) < len(blockMetadata.ConsenterIds) {
   438  		// adding new node
   439  		raftConfChange.Type = raftpb.ConfChangeAddNode
   440  		for _, consenterID := range blockMetadata.ConsenterIds {
   441  			if NodeExists(consenterID, confState.Nodes) {
   442  				continue
   443  			}
   444  			raftConfChange.NodeID = consenterID
   445  		}
   446  	} else {
   447  		// removing node
   448  		raftConfChange.Type = raftpb.ConfChangeRemoveNode
   449  		for _, nodeID := range confState.Nodes {
   450  			if NodeExists(nodeID, blockMetadata.ConsenterIds) {
   451  				continue
   452  			}
   453  			raftConfChange.NodeID = nodeID
   454  		}
   455  	}
   456  
   457  	return raftConfChange
   458  }
   459  
   460  // CreateConsentersMap creates a map of Raft Node IDs to Consenter given the block metadata and the config metadata.
   461  func CreateConsentersMap(blockMetadata *etcdraft.BlockMetadata, configMetadata *etcdraft.ConfigMetadata) map[uint64]*etcdraft.Consenter {
   462  	consenters := map[uint64]*etcdraft.Consenter{}
   463  	for i, consenter := range configMetadata.Consenters {
   464  		consenters[blockMetadata.ConsenterIds[i]] = consenter
   465  	}
   466  	return consenters
   467  }