68 lines
2.2 KiB
Go
68 lines
2.2 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package deliver
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric/common/util"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// BindingInspector receives as parameters a gRPC context and an Envelope,
|
|
// and verifies whether the message contains an appropriate binding to the context
|
|
type BindingInspector func(context.Context, proto.Message) error
|
|
|
|
// CertHashExtractor extracts a certificate from a proto.Message message
|
|
type CertHashExtractor func(proto.Message) []byte
|
|
|
|
// NewBindingInspector returns a BindingInspector according to whether
|
|
// mutualTLS is configured or not, and according to a function that extracts
|
|
// TLS certificate hashes from proto messages
|
|
func NewBindingInspector(mutualTLS bool, extractTLSCertHash CertHashExtractor) BindingInspector {
|
|
if extractTLSCertHash == nil {
|
|
panic(errors.New("extractTLSCertHash parameter is nil"))
|
|
}
|
|
inspectMessage := mutualTLSBinding
|
|
if !mutualTLS {
|
|
inspectMessage = noopBinding
|
|
}
|
|
return func(ctx context.Context, msg proto.Message) error {
|
|
if msg == nil {
|
|
return errors.New("message is nil")
|
|
}
|
|
return inspectMessage(ctx, extractTLSCertHash(msg))
|
|
}
|
|
}
|
|
|
|
// mutualTLSBinding enforces the client to send its TLS cert hash in the message,
|
|
// and then compares it to the computed hash that is derived
|
|
// from the gRPC context.
|
|
// In case they don't match, or the cert hash is missing from the request or
|
|
// there is no TLS certificate to be excavated from the gRPC context,
|
|
// an error is returned.
|
|
func mutualTLSBinding(ctx context.Context, claimedTLScertHash []byte) error {
|
|
if len(claimedTLScertHash) == 0 {
|
|
return errors.Errorf("client didn't include its TLS cert hash")
|
|
}
|
|
actualTLScertHash := util.ExtractCertificateHashFromContext(ctx)
|
|
if len(actualTLScertHash) == 0 {
|
|
return errors.Errorf("client didn't send a TLS certificate")
|
|
}
|
|
if !bytes.Equal(actualTLScertHash, claimedTLScertHash) {
|
|
return errors.Errorf("claimed TLS cert hash is %v but actual TLS cert hash is %v", claimedTLScertHash, actualTLScertHash)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// noopBinding is a BindingInspector that always returns nil
|
|
func noopBinding(_ context.Context, _ []byte) error {
|
|
return nil
|
|
}
|