Commit 53de0781 authored by Alessandro Sorniotti's avatar Alessandro Sorniotti
Browse files

[FAB-6381] Secure defaults for txsFilter



The aim of this change set is to apply the well-established "Secure by
default" security principle to the way the validator validates transactions
in a block.

The current code behaves as follows: create an array of validation codes, set
by default to "all transactions are valid"; then perform validation which may
mark transactions as invalid. Furthermore, in other parts of the code, if no
array of validation codes is yet persent in the block, a new one is
indiscriminately created (again, marking all transactions as valid). This
approach is a security anti-pattern because it opens up to attacks where an
adversary may force the code through a path where the default "tx is valid"
validation code is maintained even for invalid txes.

This change set ensures that validation code arrays are created and set to a
new value (TxValidationCode_NOT_VALIDATED) which ensures that a transaction
that hasn't been validated cannot be mistaken for a valid one.

Change-Id: I5dbb18dd77af3cd14b168042ae660e4e27bf29dd
Signed-off-by: default avatarAlessandro Sorniotti <ale.linux@sopit.net>
parent 631ab5b1
......@@ -13,8 +13,10 @@ import (
"github.com/hyperledger/fabric/common/tools/configtxgen/configtxgentest"
"github.com/hyperledger/fabric/common/tools/configtxgen/encoder"
genesisconfig "github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
"github.com/hyperledger/fabric/core/ledger/util"
cb "github.com/hyperledger/fabric/protos/common"
mspproto "github.com/hyperledger/fabric/protos/msp"
"github.com/hyperledger/fabric/protos/peer"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
)
......@@ -29,7 +31,15 @@ func MakeGenesisBlock(chainID string) (*cb.Block, error) {
logger.Panicf("Error creating channel config: %s", err)
}
return genesis.NewFactoryImpl(channelGroup).Block(chainID)
gb, err := genesis.NewFactoryImpl(channelGroup).Block(chainID)
if err != nil || gb == nil {
return gb, err
}
txsFilter := util.NewTxValidationFlagsSetValue(len(gb.Data.Data), peer.TxValidationCode_VALID)
gb.Metadata.Metadata[cb.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
return gb, nil
}
// MakeGenesisBlockWithMSPs creates a genesis block using the MSPs provided for the given chainID
......
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Copyright IBM Corp. 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.
SPDX-License-Identifier: Apache-2.0
*/
package testutil
......@@ -41,7 +31,7 @@ type BlockGenerator struct {
func NewBlockGenerator(t *testing.T, ledgerID string, signTxs bool) (*BlockGenerator, *common.Block) {
gb, err := test.MakeGenesisBlock(ledgerID)
AssertNoError(t, err, "")
gb.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = lutils.NewTxValidationFlags(len(gb.Data.Data))
gb.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = lutils.NewTxValidationFlagsSetValue(len(gb.Data.Data), pb.TxValidationCode_VALID)
return &BlockGenerator{1, gb.GetHeader().Hash(), signTxs, t}, gb
}
......@@ -164,7 +154,7 @@ func NewBlock(env []*common.Envelope, blockNum uint64, previousHash []byte) *com
block.Header.DataHash = block.Data.Hash()
utils.InitBlockMetadata(block)
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = lutils.NewTxValidationFlags(len(env))
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = lutils.NewTxValidationFlagsSetValue(len(env), pb.TxValidationCode_VALID)
return block
}
......@@ -39,6 +39,7 @@ import (
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
cut "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/ledger/util/couchdb"
cmp "github.com/hyperledger/fabric/core/mocks/peer"
"github.com/hyperledger/fabric/core/peer"
......@@ -294,6 +295,9 @@ func endTxSimulation(chainID string, ccid *pb.ChaincodeID, txsim ledger.TxSimula
//create the block with 1 transaction
block := common.NewBlock(blockNumber, []byte{})
block.Data.Data = [][]byte{envBytes}
txsFilter := cut.NewTxValidationFlagsSetValue(len(block.Data.Data), pb.TxValidationCode_VALID)
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
//commit the block
//see comment on _commitLock_
......
......@@ -18,6 +18,7 @@ import (
"github.com/hyperledger/fabric/common/tools/configtxgen/encoder"
"github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
ledger2 "github.com/hyperledger/fabric/core/ledger"
cut "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/peer"
"github.com/stretchr/testify/assert"
......@@ -182,6 +183,8 @@ func TestNewLedgerCommitterReactive(t *testing.T) {
profile := configtxgentest.Load(localconfig.SampleSingleMSPSoloProfile)
block := encoder.New(profile).GenesisBlockForChannel(chainID)
txsFilter := cut.NewTxValidationFlagsSetValue(len(block.Data.Data), peer.TxValidationCode_VALID)
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
err = committer.CommitWithPvtData(&ledger2.BlockAndPvtData{
Block: block,
......
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Copyright IBM Corp. 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.
SPDX-License-Identifier: Apache-2.0
*/
package txvalidator
......@@ -87,24 +77,24 @@ func TestDetectTXIdDuplicates(t *testing.T) {
txids := []string{"", "1", "2", "3", "", "2", ""}
txsfltr := ledgerUtil.NewTxValidationFlags(len(txids))
markTXIdDuplicates(txids, txsfltr)
assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_DUPLICATE_TXID))
assert.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_NOT_VALIDATED))
txids = []string{"", "1", "2", "3", "", "21", ""}
txsfltr = ledgerUtil.NewTxValidationFlags(len(txids))
markTXIdDuplicates(txids, txsfltr)
assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_VALID))
assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(1, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(2, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(3, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(4, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(5, peer.TxValidationCode_NOT_VALIDATED))
assert.True(t, txsfltr.IsSetTo(6, peer.TxValidationCode_NOT_VALIDATED))
}
func TestBlockValidationDuplicateTXId(t *testing.T) {
......@@ -267,6 +257,9 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
// Initialize metadata
utils.InitBlockMetadata(block)
txsFilter := util.NewTxValidationFlagsSetValue(len(block.Data.Data), peer.TxValidationCode_VALID)
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
// Commit block to the ledger
ledger.CommitWithPvtData(&ledger2.BlockAndPvtData{
Block: block,
......
......@@ -208,6 +208,12 @@ func (v *txValidator) Validate(block *common.Block) error {
// success
v.invalidTXsForUpgradeCC(txsChaincodeNames, txsUpgradedChaincodes, txsfltr)
// make sure no transaction has skipped validation
err = v.allValidated(txsfltr, block)
if err != nil {
return err
}
// Initialize metadata structure
utils.InitBlockMetadata(block)
......@@ -216,6 +222,18 @@ func (v *txValidator) Validate(block *common.Block) error {
return nil
}
// allValidated returns error if some of the validation flags have not been set
// during validation
func (v *txValidator) allValidated(txsfltr ledgerUtil.TxValidationFlags, block *common.Block) error {
for id, f := range txsfltr {
if peer.TxValidationCode(f) == peer.TxValidationCode_NOT_VALIDATED {
return errors.Errorf("transaction %d in block %d has skipped validation", id, block.Header.Number)
}
}
return nil
}
func markTXIdDuplicates(txids []string, txsfltr ledgerUtil.TxValidationFlags) {
txidMap := make(map[string]struct{})
......
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Copyright IBM Corp. 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.
SPDX-License-Identifier: Apache-2.0
*/
package historyleveldb
......@@ -94,11 +84,6 @@ func (historyDB *historyDB) Commit(block *common.Block) error {
// Get the invalidation byte array for the block
txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
// Initialize txsFilter if it does not yet exist (e.g. during testing, for genesis block, etc)
if len(txsFilter) == 0 {
txsFilter = util.NewTxValidationFlags(len(block.Data.Data))
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
}
// write each tran's write set to history db
for _, envBytes := range block.Data.Data {
......
......@@ -92,11 +92,6 @@ func preprocessProtoBlock(txmgr txmgr.TxMgr, block *common.Block, doMVCCValidati
b := &valinternal.Block{Num: block.Header.Number}
// Committer validator has already set validation flags based on well formed tran checks
txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
// Precaution in case committer validator has not added validation flags yet
if len(txsFilter) == 0 {
txsFilter = util.NewTxValidationFlags(len(block.Data.Data))
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
}
for txIndex, envBytes := range block.Data.Data {
var env *common.Envelope
var chdr *common.ChannelHeader
......
......@@ -31,7 +31,7 @@ func TestPreprocessProtoBlock(t *testing.T) {
gb = testutil.ConstructTestBlock(t, 11, 1, 1)
gb.Data = &common.BlockData{Data: [][]byte{{123}}}
gb.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] =
lutils.NewTxValidationFlags(len(gb.Data.Data))
lutils.NewTxValidationFlagsSetValue(len(gb.Data.Data), peer.TxValidationCode_VALID)
_, err = preprocessProtoBlock(nil, gb, false)
assert.Error(t, err)
t.Log(err)
......
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Copyright IBM Corp. 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.
SPDX-License-Identifier: Apache-2.0
*/
package util
......@@ -23,9 +13,24 @@ import (
// TxValidationFlags is array of transaction validation codes. It is used when committer validates block.
type TxValidationFlags []uint8
// NewTxValidationFlags Create new object-array of validation codes with target size. Default values: valid.
// NewTxValidationFlags Create new object-array of validation codes with target size.
// Default values: TxValidationCode_NOT_VALIDATED
func NewTxValidationFlags(size int) TxValidationFlags {
return newTxValidationFlagsSetValue(size, peer.TxValidationCode_NOT_VALIDATED)
}
// NewTxValidationFlagsSetValue Creates new object-array of validation codes with target size
// and the supplied value
func NewTxValidationFlagsSetValue(size int, value peer.TxValidationCode) TxValidationFlags {
return newTxValidationFlagsSetValue(size, value)
}
func newTxValidationFlagsSetValue(size int, value peer.TxValidationCode) TxValidationFlags {
inst := make(TxValidationFlags, size)
for i := range inst {
inst[i] = uint8(value)
}
return inst
}
......
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Copyright IBM Corp. 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.
SPDX-License-Identifier: Apache-2.0
*/
package util
......@@ -24,7 +14,7 @@ import (
)
func TestTransactionValidationFlags(t *testing.T) {
txFlags := NewTxValidationFlags(10)
txFlags := NewTxValidationFlagsSetValue(10, peer.TxValidationCode_VALID)
assert.Equal(t, 10, len(txFlags))
txFlags.SetFlag(0, peer.TxValidationCode_VALID)
......
......@@ -26,10 +26,12 @@ import (
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
"github.com/hyperledger/fabric/core/comm"
testpb "github.com/hyperledger/fabric/core/comm/testdata/grpc"
"github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/msp"
cb "github.com/hyperledger/fabric/protos/common"
mspproto "github.com/hyperledger/fabric/protos/msp"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)
......@@ -105,7 +107,14 @@ func createMSPConfig(rootCerts, tlsRootCerts, tlsIntermediateCerts [][]byte,
func createConfigBlock(chainID string, appMSPConf, ordererMSPConf *mspproto.MSPConfig,
appOrgID, ordererOrgID string) (*cb.Block, error) {
block, err := configtxtest.MakeGenesisBlockFromMSPs(chainID, appMSPConf, ordererMSPConf, appOrgID, ordererOrgID)
return block, err
if block == nil || err != nil {
return block, err
}
txsFilter := util.NewTxValidationFlagsSetValue(len(block.Data.Data), pb.TxValidationCode_VALID)
block.Metadata.Metadata[cb.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
return block, nil
}
func TestUpdateRootsFromConfigBlock(t *testing.T) {
......
......@@ -22,6 +22,7 @@ import (
"github.com/hyperledger/fabric/core/aclmgmt/resources"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/common/sysccprovider"
"github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/core/policy"
"github.com/hyperledger/fabric/events/producer"
......@@ -138,6 +139,15 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
"for channel [%s]: [%s]", cid, err))
}
// Initialize txsFilter if it does not yet exist. We can do this safely since
// it's the genesis block anyway
txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
if len(txsFilter) == 0 {
// add array of validation code hardcoded to valid
txsFilter = util.NewTxValidationFlagsSetValue(len(block.Data.Data), pb.TxValidationCode_VALID)
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
}
return joinChain(cid, block, e.sccp)
case GetConfigBlock:
// 2. check policy
......
......@@ -41,6 +41,7 @@ const (
TxValidationCode_BAD_RESPONSE_PAYLOAD TxValidationCode = 21
TxValidationCode_BAD_RWSET TxValidationCode = 22
TxValidationCode_ILLEGAL_WRITESET TxValidationCode = 23
TxValidationCode_NOT_VALIDATED TxValidationCode = 254
TxValidationCode_INVALID_OTHER_REASON TxValidationCode = 255
)
......@@ -69,6 +70,7 @@ var TxValidationCode_name = map[int32]string{
21: "BAD_RESPONSE_PAYLOAD",
22: "BAD_RWSET",
23: "ILLEGAL_WRITESET",
254: "NOT_VALIDATED",
255: "INVALID_OTHER_REASON",
}
var TxValidationCode_value = map[string]int32{
......@@ -96,6 +98,7 @@ var TxValidationCode_value = map[string]int32{
"BAD_RESPONSE_PAYLOAD": 21,
"BAD_RWSET": 22,
"ILLEGAL_WRITESET": 23,
"NOT_VALIDATED": 254,
"INVALID_OTHER_REASON": 255,
}
......@@ -308,58 +311,58 @@ func init() {
func init() { proto.RegisterFile("peer/transaction.proto", fileDescriptor12) }
var fileDescriptor12 = []byte{
// 833 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0xd1, 0x6e, 0xe2, 0x46,
0x14, 0x2d, 0xd9, 0x4d, 0xd2, 0x0c, 0xd9, 0x64, 0x32, 0x10, 0x42, 0x50, 0xd4, 0x5d, 0xf1, 0x50,
0x6d, 0x5b, 0x09, 0xa4, 0xec, 0x43, 0xa5, 0xaa, 0x2f, 0x83, 0x3d, 0x09, 0x56, 0xcd, 0x8c, 0x35,
0x1e, 0x08, 0xe9, 0x43, 0x47, 0x06, 0xcf, 0x12, 0x54, 0xb0, 0x2d, 0xdb, 0x59, 0x35, 0xaf, 0xfd,
0x80, 0xf6, 0x3f, 0xfb, 0x13, 0xad, 0xc6, 0x63, 0x03, 0xc9, 0x76, 0x5f, 0x30, 0x73, 0xcf, 0xb9,
0xf7, 0x9c, 0x7b, 0xaf, 0x3d, 0xa0, 0x95, 0x28, 0x95, 0xf6, 0xf3, 0x34, 0x88, 0xb2, 0x60, 0x9e,
0x2f, 0xe3, 0xa8, 0x97, 0xa4, 0x71, 0x1e, 0xa3, 0x83, 0xe2, 0x91, 0x75, 0xde, 0x2e, 0xe2, 0x78,
0xb1, 0x52, 0xfd, 0xe2, 0x38, 0x7b, 0xfc, 0xd8, 0xcf, 0x97, 0x6b, 0x95, 0xe5, 0xc1, 0x3a, 0x31,
0xc4, 0xce, 0x55, 0x51, 0x20, 0x49, 0xe3, 0x24, 0xce, 0x82, 0x95, 0x4c, 0x55, 0x96, 0xc4, 0x51,
0xa6, 0x4a, 0xb4, 0x31, 0x8f, 0xd7, 0xeb, 0x38, 0xea, 0x9b, 0x87, 0x09, 0x76, 0x7f, 0x03, 0x67,
0xfe, 0x72, 0x11, 0xa9, 0x50, 0x6c, 0x65, 0xd1, 0x0f, 0xe0, 0x6c, 0xc7, 0x85, 0x9c, 0x3d, 0xe5,
0x2a, 0x6b, 0xd7, 0xde, 0xd5, 0xde, 0x1f, 0x73, 0xb8, 0x03, 0x0c, 0x74, 0x1c, 0x5d, 0x81, 0xa3,
0x6c, 0xb9, 0x88, 0x82, 0xfc, 0x31, 0x55, 0xed, 0xbd, 0x82, 0xb4, 0x0d, 0x74, 0xff, 0xac, 0x81,
0xa6, 0x97, 0xc6, 0x73, 0x95, 0x65, 0xcf, 0x35, 0x06, 0xa0, 0xb1, 0x53, 0x8a, 0x44, 0x9f, 0xd4,
0x2a, 0x4e, 0x54, 0xa1, 0x52, 0xbf, 0x86, 0xbd, 0xd2, 0x64, 0x15, 0xe7, 0xff, 0x47, 0x46, 0xdf,
0x82, 0x93, 0x4f, 0xc1, 0x6a, 0x19, 0x06, 0x3a, 0x6a, 0xc5, 0xa1, 0xd1, 0xdf, 0xe7, 0x2f, 0xa2,
0xdd, 0x01, 0xa8, 0xef, 0x4a, 0x7f, 0x00, 0x87, 0xe6, 0x9f, 0x6e, 0xea, 0xd5, 0xfb, 0xfa, 0xf5,
0xa5, 0x19, 0x46, 0xd6, 0xdb, 0x61, 0xe1, 0xe2, 0x97, 0x57, 0xcc, 0x2e, 0x01, 0x67, 0x9f, 0xa1,
0xa8, 0x05, 0x0e, 0x1e, 0x54, 0x10, 0xaa, 0xb4, 0x9c, 0x4e, 0x79, 0x42, 0x6d, 0x70, 0x98, 0x04,
0x4f, 0xab, 0x38, 0x08, 0xcb, 0x89, 0x54, 0xc7, 0xee, 0xdf, 0x35, 0xd0, 0xb2, 0x1e, 0x82, 0x65,
0x34, 0x8f, 0x43, 0x65, 0xaa, 0x78, 0x06, 0x42, 0x3f, 0x83, 0xce, 0xbc, 0x42, 0xe4, 0x66, 0x89,
0x55, 0x1d, 0x23, 0xd0, 0xde, 0x30, 0xbc, 0x92, 0x50, 0x65, 0xff, 0x08, 0x0e, 0x8c, 0xb5, 0x42,
0xb1, 0x7e, 0xfd, 0xb6, 0xea, 0x69, 0xa3, 0x46, 0xa2, 0x30, 0x4e, 0x33, 0x15, 0x96, 0x9d, 0x95,
0xf4, 0xee, 0x5f, 0x35, 0x70, 0xf1, 0x05, 0x0e, 0xfa, 0x09, 0x5c, 0x7e, 0xf6, 0x36, 0xbd, 0x70,
0x74, 0x51, 0x11, 0x78, 0x89, 0x6f, 0x0d, 0x1d, 0x2b, 0x53, 0x6d, 0xad, 0xa2, 0x3c, 0x6b, 0xef,
0x15, 0xa3, 0x6e, 0x54, 0xb6, 0xc8, 0x16, 0xe3, 0xcf, 0x88, 0xdf, 0xff, 0xf3, 0x1a, 0x40, 0xf1,
0xc7, 0xe4, 0xd9, 0x0a, 0xd1, 0x11, 0xd8, 0x9f, 0x60, 0xd7, 0xb1, 0xe1, 0x57, 0x08, 0x82, 0x63,
0xea, 0xb8, 0x92, 0xd0, 0x09, 0x71, 0x99, 0x47, 0x60, 0x0d, 0x9d, 0x82, 0xfa, 0x00, 0xdb, 0xd2,
0xc3, 0xf7, 0x2e, 0xc3, 0x36, 0xdc, 0x43, 0xe7, 0xe0, 0x4c, 0x07, 0x2c, 0x36, 0x1a, 0x31, 0x2a,
0x87, 0x04, 0xdb, 0x84, 0xc3, 0x57, 0xe8, 0x12, 0x9c, 0x17, 0x61, 0x4e, 0xb0, 0x60, 0x5c, 0xfa,
0xce, 0x2d, 0xc5, 0x62, 0xcc, 0x09, 0x7c, 0x8d, 0xde, 0x81, 0x2b, 0x87, 0x16, 0x0a, 0x92, 0x50,
0x9b, 0x71, 0x9f, 0x70, 0x29, 0x38, 0xa6, 0x3e, 0xb6, 0x84, 0xc3, 0x28, 0xdc, 0x47, 0xdf, 0x80,
0x4e, 0xc5, 0xb0, 0x18, 0xbd, 0x71, 0x6e, 0x9f, 0xe1, 0x07, 0xa8, 0x03, 0x5a, 0x63, 0xea, 0x8f,
0x3d, 0x8f, 0x71, 0x41, 0x6c, 0x29, 0xa6, 0x1b, 0x3f, 0x87, 0x95, 0x1f, 0x8f, 0x33, 0x8f, 0xf9,
0xd8, 0x95, 0x62, 0xea, 0xd8, 0xf0, 0x6b, 0x84, 0xc0, 0x89, 0x3d, 0xf6, 0x5c, 0xc7, 0xc2, 0x82,
0x98, 0xd8, 0x91, 0x96, 0x29, 0x0d, 0x8c, 0x08, 0x15, 0xd2, 0x63, 0xae, 0x63, 0xdd, 0xcb, 0x1b,
0xec, 0xb8, 0xda, 0x28, 0x40, 0x2d, 0x80, 0x46, 0x13, 0xcb, 0x92, 0x9c, 0x60, 0x63, 0xc4, 0x75,
0x2c, 0x01, 0xeb, 0xba, 0x37, 0x6f, 0x88, 0xa9, 0x60, 0xa3, 0x17, 0xd0, 0x31, 0x6a, 0x80, 0xd3,
0x31, 0xfd, 0x85, 0xb2, 0x3b, 0xaa, 0x5d, 0x89, 0x7b, 0x8f, 0xc0, 0x37, 0xda, 0xae, 0xc0, 0xfc,
0x96, 0x08, 0x69, 0x0d, 0xb1, 0x43, 0x25, 0x65, 0x42, 0xde, 0xb0, 0x31, 0xb5, 0xe1, 0x09, 0x6a,
0x02, 0x38, 0xc2, 0xdc, 0x1f, 0x16, 0x4e, 0x25, 0xe1, 0x9c, 0x71, 0x78, 0x5a, 0xcd, 0x5d, 0x4c,
0xcb, 0x96, 0xa1, 0x6e, 0x8b, 0x4c, 0x3d, 0x87, 0x13, 0xdb, 0x14, 0xb1, 0x98, 0x4d, 0xe0, 0x99,
0x6e, 0x61, 0x73, 0x94, 0x13, 0xc2, 0x7d, 0x87, 0xd1, 0xad, 0x1f, 0x84, 0xda, 0xa0, 0xa9, 0xa7,
0x61, 0xd6, 0x22, 0xc9, 0x54, 0x10, 0xaa, 0x29, 0xb0, 0xa1, 0x9b, 0x2b, 0x16, 0x34, 0xc4, 0x94,
0x12, 0xb7, 0x5a, 0x5c, 0xb3, 0xca, 0xe0, 0xc4, 0xf7, 0x18, 0xf5, 0xc9, 0x66, 0xb2, 0xe7, 0xe8,
0x0d, 0x38, 0x2a, 0x90, 0x3b, 0x9f, 0x08, 0xd8, 0xd2, 0xce, 0x1d, 0xd7, 0x25, 0xb7, 0xd8, 0x95,
0x77, 0xdc, 0x11, 0x44, 0x47, 0x2f, 0xd0, 0x25, 0x68, 0x56, 0xab, 0x63, 0x62, 0x48, 0xb8, 0x9e,
0x90, 0xcf, 0x28, 0xfc, 0xb7, 0x36, 0x98, 0x83, 0x6e, 0x9c, 0x2e, 0x7a, 0x0f, 0x4f, 0x89, 0x4a,
0x57, 0x2a, 0x5c, 0xa8, 0xb4, 0xf7, 0x31, 0x98, 0xa5, 0xcb, 0x79, 0xf5, 0x9e, 0xea, 0x2b, 0x75,
0x80, 0x76, 0x3e, 0x7d, 0x2f, 0x98, 0xff, 0x1e, 0x2c, 0xd4, 0xaf, 0xdf, 0x2d, 0x96, 0xf9, 0xc3,
0xe3, 0x4c, 0xdf, 0x54, 0xfd, 0x9d, 0xf4, 0xbe, 0x49, 0x37, 0x97, 0x74, 0xd6, 0xd7, 0xe9, 0x33,
0x73, 0x81, 0x7f, 0xf8, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x19, 0x1c, 0xb2, 0xe4, 0xe1, 0x05, 0x00,
0x00,
// 843 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0x5d, 0x6f, 0x22, 0x37,
0x14, 0x2d, 0xd9, 0x4d, 0xd2, 0x5c, 0xf2, 0x61, 0x0c, 0x21, 0x04, 0x45, 0xdd, 0x15, 0x0f, 0xd5,
0xb6, 0x95, 0x40, 0xca, 0x3e, 0x54, 0xaa, 0xfa, 0x62, 0x66, 0x9c, 0x30, 0xea, 0x60, 0x8f, 0x3c,
0x86, 0x90, 0x3e, 0xd4, 0x1a, 0xc0, 0x4b, 0x50, 0x61, 0x06, 0xcd, 0x90, 0x55, 0xf3, 0xda, 0x1f,
0xd0, 0xfe, 0xe3, 0x6d, 0xe5, 0xf9, 0x00, 0x92, 0xb4, 0x2f, 0x0c, 0xbe, 0xe7, 0xf8, 0x9e, 0x73,
0xef, 0xb5, 0x2e, 0xd4, 0x57, 0x5a, 0xc7, 0x9d, 0x75, 0x1c, 0x84, 0x49, 0x30, 0x59, 0xcf, 0xa3,
0xb0, 0xbd, 0x8a, 0xa3, 0x75, 0x84, 0x0f, 0xd2, 0x4f, 0xd2, 0x7c, 0x37, 0x8b, 0xa2, 0xd9, 0x42,
0x77, 0xd2, 0xe3, 0xf8, 0xf1, 0x53, 0x67, 0x3d, 0x5f, 0xea, 0x64, 0x1d, 0x2c, 0x57, 0x19, 0xb1,
0x79, 0x95, 0x26, 0x58, 0xc5, 0xd1, 0x2a, 0x4a, 0x82, 0x85, 0x8a, 0x75, 0xb2, 0x8a, 0xc2, 0x44,
0xe7, 0x68, 0x75, 0x12, 0x2d, 0x97, 0x51, 0xd8, 0xc9, 0x3e, 0x59, 0xb0, 0xf5, 0x1b, 0x54, 0xfc,
0xf9, 0x2c, 0xd4, 0x53, 0xb9, 0x95, 0xc5, 0x3f, 0x40, 0x65, 0xc7, 0x85, 0x1a, 0x3f, 0xad, 0x75,
0xd2, 0x28, 0xbd, 0x2f, 0x7d, 0x38, 0x16, 0x68, 0x07, 0xe8, 0x9a, 0x38, 0xbe, 0x82, 0xa3, 0x64,
0x3e, 0x0b, 0x83, 0xf5, 0x63, 0xac, 0x1b, 0x7b, 0x29, 0x69, 0x1b, 0x68, 0xfd, 0x59, 0x82, 0x9a,
0x17, 0x47, 0x13, 0x9d, 0x24, 0xcf, 0x35, 0xba, 0x50, 0xdd, 0x49, 0x45, 0xc3, 0xcf, 0x7a, 0x11,
0xad, 0x74, 0xaa, 0x52, 0xbe, 0x46, 0xed, 0xdc, 0x64, 0x11, 0x17, 0xff, 0x45, 0xc6, 0xdf, 0xc2,
0xe9, 0xe7, 0x60, 0x31, 0x9f, 0x06, 0x26, 0x6a, 0x45, 0xd3, 0x4c, 0x7f, 0x5f, 0xbc, 0x88, 0xb6,
0xba, 0x50, 0xde, 0x95, 0xfe, 0x08, 0x87, 0xd9, 0x3f, 0x53, 0xd4, 0x9b, 0x0f, 0xe5, 0xeb, 0xcb,
0xac, 0x19, 0x49, 0x7b, 0x87, 0x45, 0xd2, 0x5f, 0x51, 0x30, 0x5b, 0x14, 0x2a, 0xaf, 0x50, 0x5c,
0x87, 0x83, 0x07, 0x1d, 0x4c, 0x75, 0x9c, 0x77, 0x27, 0x3f, 0xe1, 0x06, 0x1c, 0xae, 0x82, 0xa7,
0x45, 0x14, 0x4c, 0xf3, 0x8e, 0x14, 0xc7, 0xd6, 0xdf, 0x25, 0xa8, 0x5b, 0x0f, 0xc1, 0x3c, 0x9c,
0x44, 0x53, 0x9d, 0x65, 0xf1, 0x32, 0x08, 0xff, 0x0c, 0xcd, 0x49, 0x81, 0xa8, 0xcd, 0x10, 0x8b,
0x3c, 0x99, 0x40, 0x63, 0xc3, 0xf0, 0x72, 0x42, 0x71, 0xfb, 0x47, 0x38, 0xc8, 0xac, 0xa5, 0x8a,
0xe5, 0xeb, 0x77, 0x45, 0x4d, 0x1b, 0x35, 0x1a, 0x4e, 0xa3, 0x38, 0xd1, 0xd3, 0xbc, 0xb2, 0x9c,
0xde, 0xfa, 0xab, 0x04, 0x17, 0xff, 0xc3, 0xc1, 0x3f, 0xc1, 0xe5, 0xab, 0xd7, 0xf4, 0xc2, 0xd1,
0x45, 0x41, 0x10, 0x39, 0xbe, 0x35, 0x74, 0xac, 0xb3, 0x6c, 0x4b, 0x1d, 0xae, 0x93, 0xc6, 0x5e,
0xda, 0xea, 0x6a, 0x61, 0x8b, 0x6e, 0x31, 0xf1, 0x8c, 0xf8, 0xfd, 0x97, 0xb7, 0x80, 0xe4, 0x1f,
0xc3, 0x67, 0x23, 0xc4, 0x47, 0xb0, 0x3f, 0x24, 0xae, 0x63, 0xa3, 0xaf, 0x30, 0x82, 0x63, 0xe6,
0xb8, 0x8a, 0xb2, 0x21, 0x75, 0xb9, 0x47, 0x51, 0x09, 0x9f, 0x41, 0xb9, 0x4b, 0x6c, 0xe5, 0x91,
0x7b, 0x97, 0x13, 0x1b, 0xed, 0xe1, 0x73, 0xa8, 0x98, 0x80, 0xc5, 0xfb, 0x7d, 0xce, 0x54, 0x8f,
0x12, 0x9b, 0x0a, 0xf4, 0x06, 0x5f, 0xc2, 0x79, 0x1a, 0x16, 0x94, 0x48, 0x2e, 0x94, 0xef, 0xdc,
0x32, 0x22, 0x07, 0x82, 0xa2, 0xb7, 0xf8, 0x3d, 0x5c, 0x39, 0x2c, 0x55, 0x50, 0x94, 0xd9, 0x5c,
0xf8, 0x54, 0x28, 0x29, 0x08, 0xf3, 0x89, 0x25, 0x1d, 0xce, 0xd0, 0x3e, 0xfe, 0x06, 0x9a, 0x05,
0xc3, 0xe2, 0xec, 0xc6, 0xb9, 0x7d, 0x86, 0x1f, 0xe0, 0x26, 0xd4, 0x07, 0xcc, 0x1f, 0x78, 0x1e,
0x17, 0x92, 0xda, 0x4a, 0x8e, 0x36, 0x7e, 0x0e, 0x0b, 0x3f, 0x9e, 0xe0, 0x1e, 0xf7, 0x89, 0xab,
0xe4, 0xc8, 0xb1, 0xd1, 0xd7, 0x18, 0xc3, 0xa9, 0x3d, 0xf0, 0x5c, 0xc7, 0x22, 0x92, 0x66, 0xb1,
0x23, 0x23, 0x93, 0x1b, 0xe8, 0x53, 0x26, 0x95, 0xc7, 0x5d, 0xc7, 0xba, 0x57, 0x37, 0xc4, 0x71,
0x8d, 0x51, 0xc0, 0x75, 0xc0, 0xfd, 0xa1, 0x65, 0x29, 0x41, 0x49, 0x66, 0xc4, 0x75, 0x2c, 0x89,
0xca, 0xa6, 0x36, 0xaf, 0x47, 0x98, 0xe4, 0xfd, 0x17, 0xd0, 0x31, 0xae, 0xc2, 0xd9, 0x80, 0xfd,
0xc2, 0xf8, 0x1d, 0x33, 0xae, 0xe4, 0xbd, 0x47, 0xd1, 0x89, 0xb1, 0x2b, 0x89, 0xb8, 0xa5, 0x52,
0x59, 0x3d, 0xe2, 0x30, 0xc5, 0xb8, 0x54, 0x37, 0x7c, 0xc0, 0x6c, 0x74, 0x8a, 0x6b, 0x80, 0xfa,
0x44, 0xf8, 0xbd, 0xd4, 0xa9, 0xa2, 0x42, 0x70, 0x81, 0xce, 0x8a, 0xbe, 0xcb, 0x51, 0x5e, 0x32,
0x32, 0x65, 0xd1, 0x91, 0xe7, 0x08, 0x6a, 0x67, 0x49, 0x2c, 0x6e, 0x53, 0x54, 0x31, 0x25, 0x6c,
0x8e, 0x6a, 0x48, 0x85, 0xef, 0x70, 0xb6, 0xf5, 0x83, 0x71, 0x03, 0x6a, 0xa6, 0x1b, 0xd9, 0x58,
0x14, 0x1d, 0x49, 0xca, 0x0c, 0x05, 0x55, 0x4d, 0x71, 0xe9, 0x80, 0x7a, 0x84, 0x31, 0xea, 0x16,
0x83, 0xab, 0x15, 0x37, 0x04, 0xf5, 0x3d, 0xce, 0x7c, 0xba, 0xe9, 0xec, 0x39, 0x3e, 0x81, 0xa3,
0x14, 0xb9, 0xf3, 0xa9, 0x44, 0x75, 0xe3, 0xdc, 0x71, 0x5d, 0x7a, 0x4b, 0x5c, 0x75, 0x27, 0x1c,
0x49, 0x4d, 0xf4, 0x02, 0x63, 0x38, 0x31, 0xe5, 0xa5, 0xc3, 0x23, 0x92, 0xda, 0xe8, 0x4b, 0x09,
0x5f, 0x42, 0xad, 0x18, 0x27, 0x97, 0x3d, 0x2a, 0x4c, 0xd7, 0x7c, 0xce, 0xd0, 0x3f, 0xa5, 0xee,
0x04, 0x5a, 0x51, 0x3c, 0x6b, 0x3f, 0x3c, 0xad, 0x74, 0xbc, 0xd0, 0xd3, 0x99, 0x8e, 0xdb, 0x9f,
0x82, 0x71, 0x3c, 0x9f, 0x14, 0x6f, 0xd7, 0xac, 0xd9, 0x2e, 0xde, 0x59, 0x07, 0x5e, 0x30, 0xf9,