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 }