6 Star 46 Fork 28

Hyperledger/fabric

Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
Clone or Download
identity.go 7.51 KB
Copy Edit Raw Blame History
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package identity
import (
"bytes"
"sync"
"sync/atomic"
"time"
"github.com/hyperledger/fabric/gossip/api"
"github.com/hyperledger/fabric/gossip/common"
errors "github.com/pkg/errors"
)
var (
// identityUsageThreshold sets the maximum time that an identity
// can not be used to verify some signature before it will be deleted
usageThreshold = time.Hour
)
// Mapper holds mappings between pkiID
// to certificates(identities) of peers
type Mapper interface {
// Put associates an identity to its given pkiID, and returns an error
// in case the given pkiID doesn't match the identity
Put(pkiID common.PKIidType, identity api.PeerIdentityType) error
// Get returns the identity of a given pkiID, or error if such an identity
// isn't found
Get(pkiID common.PKIidType) (api.PeerIdentityType, error)
// Sign signs a message, returns a signed message on success
// or an error on failure
Sign(msg []byte) ([]byte, error)
// Verify verifies a signed message
Verify(vkID, signature, message []byte) error
// GetPKIidOfCert returns the PKI-ID of a certificate
GetPKIidOfCert(api.PeerIdentityType) common.PKIidType
// SuspectPeers re-validates all peers that match the given predicate
SuspectPeers(isSuspected api.PeerSuspector)
// Stop stops all background computations of the Mapper
Stop()
}
type purgeTrigger func(pkiID common.PKIidType, identity api.PeerIdentityType)
// identityMapperImpl is a struct that implements Mapper
type identityMapperImpl struct {
onPurge purgeTrigger
mcs api.MessageCryptoService
pkiID2Cert map[string]*storedIdentity
sync.RWMutex
stopChan chan struct{}
sync.Once
selfPKIID string
}
// NewIdentityMapper method, all we need is a reference to a MessageCryptoService
func NewIdentityMapper(mcs api.MessageCryptoService, selfIdentity api.PeerIdentityType, onPurge purgeTrigger) Mapper {
selfPKIID := mcs.GetPKIidOfCert(selfIdentity)
idMapper := &identityMapperImpl{
onPurge: onPurge,
mcs: mcs,
pkiID2Cert: make(map[string]*storedIdentity),
stopChan: make(chan struct{}),
selfPKIID: string(selfPKIID),
}
if err := idMapper.Put(selfPKIID, selfIdentity); err != nil {
panic(errors.Wrap(err, "Failed putting our own identity into the identity mapper"))
}
go idMapper.periodicalPurgeUnusedIdentities()
return idMapper
}
func (is *identityMapperImpl) periodicalPurgeUnusedIdentities() {
for {
select {
case <-is.stopChan:
return
case <-time.After(usageThreshold / 10):
is.SuspectPeers(func(_ api.PeerIdentityType) bool {
return false
})
}
}
}
// put associates an identity to its given pkiID, and returns an error
// in case the given pkiID doesn't match the identity
func (is *identityMapperImpl) Put(pkiID common.PKIidType, identity api.PeerIdentityType) error {
if pkiID == nil {
return errors.New("PKIID is nil")
}
if identity == nil {
return errors.New("identity is nil")
}
expirationDate, err := is.mcs.Expiration(identity)
if err != nil {
return errors.Wrap(err, "failed classifying identity")
}
if err := is.mcs.ValidateIdentity(identity); err != nil {
return err
}
id := is.mcs.GetPKIidOfCert(identity)
if !bytes.Equal(pkiID, id) {
return errors.New("identity doesn't match the computed pkiID")
}
is.Lock()
defer is.Unlock()
// Check if identity already exists.
// If so, no need to overwrite it.
if _, exists := is.pkiID2Cert[string(pkiID)]; exists {
return nil
}
var expirationTimer *time.Timer
if !expirationDate.IsZero() {
if time.Now().After(expirationDate) {
return errors.New("identity expired")
}
// Identity would be wiped out a millisecond after its expiration date
timeToLive := expirationDate.Add(time.Millisecond).Sub(time.Now())
expirationTimer = time.AfterFunc(timeToLive, func() {
is.delete(pkiID, identity)
})
}
is.pkiID2Cert[string(id)] = newStoredIdentity(pkiID, identity, expirationTimer)
return nil
}
// get returns the identity of a given pkiID, or error if such an identity
// isn't found
func (is *identityMapperImpl) Get(pkiID common.PKIidType) (api.PeerIdentityType, error) {
is.RLock()
defer is.RUnlock()
storedIdentity, exists := is.pkiID2Cert[string(pkiID)]
if !exists {
return nil, errors.New("PKIID wasn't found")
}
return storedIdentity.fetchIdentity(), nil
}
// Sign signs a message, returns a signed message on success
// or an error on failure
func (is *identityMapperImpl) Sign(msg []byte) ([]byte, error) {
return is.mcs.Sign(msg)
}
func (is *identityMapperImpl) Stop() {
is.Once.Do(func() {
is.stopChan <- struct{}{}
})
}
// Verify verifies a signed message
func (is *identityMapperImpl) Verify(vkID, signature, message []byte) error {
cert, err := is.Get(vkID)
if err != nil {
return err
}
return is.mcs.Verify(cert, signature, message)
}
// GetPKIidOfCert returns the PKI-ID of a certificate
func (is *identityMapperImpl) GetPKIidOfCert(identity api.PeerIdentityType) common.PKIidType {
return is.mcs.GetPKIidOfCert(identity)
}
// SuspectPeers re-validates all peers that match the given predicate
func (is *identityMapperImpl) SuspectPeers(isSuspected api.PeerSuspector) {
for _, identity := range is.validateIdentities(isSuspected) {
identity.cancelExpirationTimer()
is.delete(identity.pkiID, identity.peerIdentity)
}
}
// validateIdentities returns a list of identities that have been revoked, expired or haven't been
// used for a long time
func (is *identityMapperImpl) validateIdentities(isSuspected api.PeerSuspector) []*storedIdentity {
now := time.Now()
is.RLock()
defer is.RUnlock()
var revokedIdentities []*storedIdentity
for pkiID, storedIdentity := range is.pkiID2Cert {
if pkiID != is.selfPKIID && storedIdentity.fetchLastAccessTime().Add(usageThreshold).Before(now) {
revokedIdentities = append(revokedIdentities, storedIdentity)
continue
}
if !isSuspected(storedIdentity.peerIdentity) {
continue
}
if err := is.mcs.ValidateIdentity(storedIdentity.fetchIdentity()); err != nil {
revokedIdentities = append(revokedIdentities, storedIdentity)
}
}
return revokedIdentities
}
func (is *identityMapperImpl) delete(pkiID common.PKIidType, identity api.PeerIdentityType) {
is.Lock()
defer is.Unlock()
is.onPurge(pkiID, identity)
delete(is.pkiID2Cert, string(pkiID))
}
type storedIdentity struct {
pkiID common.PKIidType
lastAccessTime int64
peerIdentity api.PeerIdentityType
expirationTimer *time.Timer
}
func newStoredIdentity(pkiID common.PKIidType, identity api.PeerIdentityType, expirationTimer *time.Timer) *storedIdentity {
return &storedIdentity{
pkiID: pkiID,
lastAccessTime: time.Now().UnixNano(),
peerIdentity: identity,
expirationTimer: expirationTimer,
}
}
func (si *storedIdentity) fetchIdentity() api.PeerIdentityType {
atomic.StoreInt64(&si.lastAccessTime, time.Now().UnixNano())
return si.peerIdentity
}
func (si *storedIdentity) fetchLastAccessTime() time.Time {
return time.Unix(0, atomic.LoadInt64(&si.lastAccessTime))
}
func (si *storedIdentity) cancelExpirationTimer() {
if si.expirationTimer == nil {
return
}
si.expirationTimer.Stop()
}
// SetIdentityUsageThreshold sets the usage threshold of identities.
// Identities that are not used at least once during the given time
// are purged
func SetIdentityUsageThreshold(duration time.Duration) {
usageThreshold = duration
}
// GetIdentityUsageThreshold returns the usage threshold of identities.
// Identities that are not used at least once during the usage threshold
// duration are purged.
func GetIdentityUsageThreshold() time.Duration {
return usageThreshold
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/hyperledger/fabric.git
git@gitee.com:hyperledger/fabric.git
hyperledger
fabric
fabric
v1.1.0-rc1

Search