github.com/hyperledger-labs/bdls@v2.1.1+incompatible/core/chaincode/accesscontrol/access.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package accesscontrol 8 9 import ( 10 "errors" 11 "fmt" 12 13 "github.com/golang/protobuf/proto" 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 "github.com/hyperledger/fabric/common/crypto/tlsgen" 16 "github.com/hyperledger/fabric/common/flogging" 17 "google.golang.org/grpc" 18 ) 19 20 var logger = flogging.MustGetLogger("chaincode.accesscontrol") 21 22 // CertAndPrivKeyPair contains a certificate 23 // and its corresponding private key in base64 format 24 type CertAndPrivKeyPair struct { 25 // Cert is an x509 certificate 26 Cert []byte 27 // Key is a private key of the corresponding certificate 28 Key []byte 29 } 30 31 type Authenticator struct { 32 mapper *certMapper 33 } 34 35 func (auth *Authenticator) Wrap(srv pb.ChaincodeSupportServer) pb.ChaincodeSupportServer { 36 return newInterceptor(srv, auth.authenticate) 37 } 38 39 // NewAuthenticator returns a new authenticator that can wrap a chaincode service 40 func NewAuthenticator(ca tlsgen.CA) *Authenticator { 41 return &Authenticator{ 42 mapper: newCertMapper(ca.NewClientCertKeyPair), 43 } 44 } 45 46 // Generate returns a pair of certificate and private key, 47 // and associates the hash of the certificate with the given 48 // chaincode name 49 func (ac *Authenticator) Generate(ccName string) (*CertAndPrivKeyPair, error) { 50 cert, err := ac.mapper.genCert(ccName) 51 if err != nil { 52 return nil, err 53 } 54 return &CertAndPrivKeyPair{ 55 Key: cert.Key, 56 Cert: cert.Cert, 57 }, nil 58 } 59 60 func (ac *Authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error { 61 if msg.Type != pb.ChaincodeMessage_REGISTER { 62 logger.Warning("Got message", msg, "but expected a ChaincodeMessage_REGISTER message") 63 return errors.New("First message needs to be a register") 64 } 65 66 chaincodeID := &pb.ChaincodeID{} 67 err := proto.Unmarshal(msg.Payload, chaincodeID) 68 if err != nil { 69 logger.Warning("Failed unmarshaling message:", err) 70 return err 71 } 72 ccName := chaincodeID.Name 73 // Obtain certificate from stream 74 hash := extractCertificateHashFromContext(stream.Context()) 75 if len(hash) == 0 { 76 errMsg := fmt.Sprintf("TLS is active but chaincode %s didn't send certificate", ccName) 77 logger.Warning(errMsg) 78 return errors.New(errMsg) 79 } 80 // Look it up in the mapper 81 registeredName := ac.mapper.lookup(certHash(hash)) 82 if registeredName == "" { 83 errMsg := fmt.Sprintf("Chaincode %s with given certificate hash %v not found in registry", ccName, hash) 84 logger.Warning(errMsg) 85 return errors.New(errMsg) 86 } 87 if registeredName != ccName { 88 errMsg := fmt.Sprintf("Chaincode %s with given certificate hash %v belongs to a different chaincode", ccName, hash) 89 logger.Warning(errMsg) 90 return fmt.Errorf(errMsg) 91 } 92 93 logger.Debug("Chaincode", ccName, "'s authentication is authorized") 94 return nil 95 }