github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/gossip/identity/identity.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package identity 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "github.com/hyperledger/fabric/gossip/api" 28 "github.com/hyperledger/fabric/gossip/common" 29 ) 30 31 var ( 32 // identityUsageThreshold sets the maximum time that an identity 33 // can not be used to verify some signature before it will be deleted 34 usageThreshold = time.Hour 35 ) 36 37 // Mapper holds mappings between pkiID 38 // to certificates(identities) of peers 39 type Mapper interface { 40 // Put associates an identity to its given pkiID, and returns an error 41 // in case the given pkiID doesn't match the identity 42 Put(pkiID common.PKIidType, identity api.PeerIdentityType) error 43 44 // Get returns the identity of a given pkiID, or error if such an identity 45 // isn't found 46 Get(pkiID common.PKIidType) (api.PeerIdentityType, error) 47 48 // Sign signs a message, returns a signed message on success 49 // or an error on failure 50 Sign(msg []byte) ([]byte, error) 51 52 // Verify verifies a signed message 53 Verify(vkID, signature, message []byte) error 54 55 // GetPKIidOfCert returns the PKI-ID of a certificate 56 GetPKIidOfCert(api.PeerIdentityType) common.PKIidType 57 58 // ListInvalidIdentities returns a list of PKI-IDs that their corresponding 59 // peer identities have been revoked, expired or haven't been used 60 // for a long time 61 ListInvalidIdentities(isSuspected api.PeerSuspector) []common.PKIidType 62 } 63 64 // identityMapperImpl is a struct that implements Mapper 65 type identityMapperImpl struct { 66 mcs api.MessageCryptoService 67 pkiID2Cert map[string]*storedIdentity 68 sync.RWMutex 69 selfPKIID string 70 } 71 72 // NewIdentityMapper method, all we need is a reference to a MessageCryptoService 73 func NewIdentityMapper(mcs api.MessageCryptoService, selfIdentity api.PeerIdentityType) Mapper { 74 selfPKIID := mcs.GetPKIidOfCert(selfIdentity) 75 idMapper := &identityMapperImpl{ 76 mcs: mcs, 77 pkiID2Cert: make(map[string]*storedIdentity), 78 selfPKIID: string(selfPKIID), 79 } 80 if err := idMapper.Put(selfPKIID, selfIdentity); err != nil { 81 panic(fmt.Errorf("Failed putting our own identity into the identity mapper: %v", err)) 82 } 83 return idMapper 84 } 85 86 // put associates an identity to its given pkiID, and returns an error 87 // in case the given pkiID doesn't match the identity 88 func (is *identityMapperImpl) Put(pkiID common.PKIidType, identity api.PeerIdentityType) error { 89 if pkiID == nil { 90 return errors.New("PKIID is nil") 91 } 92 if identity == nil { 93 return errors.New("identity is nil") 94 } 95 96 if err := is.mcs.ValidateIdentity(identity); err != nil { 97 return err 98 } 99 100 id := is.mcs.GetPKIidOfCert(identity) 101 if !bytes.Equal(pkiID, id) { 102 return errors.New("identity doesn't match the computed pkiID") 103 } 104 105 is.Lock() 106 defer is.Unlock() 107 is.pkiID2Cert[string(id)] = newStoredIdentity(identity) 108 return nil 109 } 110 111 // get returns the identity of a given pkiID, or error if such an identity 112 // isn't found 113 func (is *identityMapperImpl) Get(pkiID common.PKIidType) (api.PeerIdentityType, error) { 114 is.RLock() 115 defer is.RUnlock() 116 storedIdentity, exists := is.pkiID2Cert[string(pkiID)] 117 if !exists { 118 return nil, errors.New("PKIID wasn't found") 119 } 120 return storedIdentity.fetchIdentity(), nil 121 } 122 123 // Sign signs a message, returns a signed message on success 124 // or an error on failure 125 func (is *identityMapperImpl) Sign(msg []byte) ([]byte, error) { 126 return is.mcs.Sign(msg) 127 } 128 129 // Verify verifies a signed message 130 func (is *identityMapperImpl) Verify(vkID, signature, message []byte) error { 131 cert, err := is.Get(vkID) 132 if err != nil { 133 return err 134 } 135 return is.mcs.Verify(cert, signature, message) 136 } 137 138 // GetPKIidOfCert returns the PKI-ID of a certificate 139 func (is *identityMapperImpl) GetPKIidOfCert(identity api.PeerIdentityType) common.PKIidType { 140 return is.mcs.GetPKIidOfCert(identity) 141 } 142 143 // ListInvalidIdentities returns a list of PKI-IDs that their corresponding 144 // peer identities have been revoked, expired or haven't been used 145 // for a long time 146 func (is *identityMapperImpl) ListInvalidIdentities(isSuspected api.PeerSuspector) []common.PKIidType { 147 revokedIds := is.validateIdentities(isSuspected) 148 if len(revokedIds) == 0 { 149 return nil 150 } 151 is.Lock() 152 defer is.Unlock() 153 for _, pkiID := range revokedIds { 154 delete(is.pkiID2Cert, string(pkiID)) 155 } 156 return revokedIds 157 } 158 159 // validateIdentities returns a list of identities that have been revoked, expired or haven't been 160 // used for a long time 161 func (is *identityMapperImpl) validateIdentities(isSuspected api.PeerSuspector) []common.PKIidType { 162 now := time.Now() 163 is.RLock() 164 defer is.RUnlock() 165 var revokedIds []common.PKIidType 166 for pkiID, storedIdentity := range is.pkiID2Cert { 167 if pkiID != is.selfPKIID && storedIdentity.fetchLastAccessTime().Add(usageThreshold).Before(now) { 168 revokedIds = append(revokedIds, common.PKIidType(pkiID)) 169 continue 170 } 171 if !isSuspected(storedIdentity.fetchIdentity()) { 172 continue 173 } 174 if err := is.mcs.ValidateIdentity(storedIdentity.fetchIdentity()); err != nil { 175 revokedIds = append(revokedIds, common.PKIidType(pkiID)) 176 } 177 } 178 return revokedIds 179 } 180 181 type storedIdentity struct { 182 lastAccessTime int64 183 peerIdentity api.PeerIdentityType 184 } 185 186 func newStoredIdentity(identity api.PeerIdentityType) *storedIdentity { 187 return &storedIdentity{ 188 lastAccessTime: time.Now().UnixNano(), 189 peerIdentity: identity, 190 } 191 } 192 193 func (si *storedIdentity) fetchIdentity() api.PeerIdentityType { 194 atomic.StoreInt64(&si.lastAccessTime, time.Now().UnixNano()) 195 return si.peerIdentity 196 } 197 198 func (si *storedIdentity) fetchLastAccessTime() time.Time { 199 return time.Unix(0, atomic.LoadInt64(&si.lastAccessTime)) 200 } 201 202 // SetIdentityUsageThreshold sets the usage threshold of identities. 203 // Identities that are not used at least once during the given time 204 // are purged 205 func SetIdentityUsageThreshold(duration time.Duration) { 206 usageThreshold = duration 207 } 208 209 // GetIdentityUsageThreshold returns the usage threshold of identities. 210 // Identities that are not used at least once during the usage threshold 211 // duration are purged. 212 func GetIdentityUsageThreshold() time.Duration { 213 return usageThreshold 214 }