github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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 "sync" 23 "time" 24 25 "sync/atomic" 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 identityUsageThreshold = 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 } 70 71 // NewIdentityMapper method, all we need is a reference to a MessageCryptoService 72 func NewIdentityMapper(mcs api.MessageCryptoService) Mapper { 73 return &identityMapperImpl{ 74 mcs: mcs, 75 pkiID2Cert: make(map[string]*storedIdentity), 76 } 77 } 78 79 // put associates an identity to its given pkiID, and returns an error 80 // in case the given pkiID doesn't match the identity 81 func (is *identityMapperImpl) Put(pkiID common.PKIidType, identity api.PeerIdentityType) error { 82 if pkiID == nil { 83 return errors.New("PKIID is nil") 84 } 85 if identity == nil { 86 return errors.New("identity is nil") 87 } 88 89 if err := is.mcs.ValidateIdentity(identity); err != nil { 90 return err 91 } 92 93 id := is.mcs.GetPKIidOfCert(identity) 94 if !bytes.Equal(pkiID, id) { 95 return errors.New("identity doesn't match the computed pkiID") 96 } 97 98 is.Lock() 99 defer is.Unlock() 100 is.pkiID2Cert[string(id)] = newStoredIdentity(identity) 101 return nil 102 } 103 104 // get returns the identity of a given pkiID, or error if such an identity 105 // isn't found 106 func (is *identityMapperImpl) Get(pkiID common.PKIidType) (api.PeerIdentityType, error) { 107 is.RLock() 108 defer is.RUnlock() 109 storedIdentity, exists := is.pkiID2Cert[string(pkiID)] 110 if !exists { 111 return nil, errors.New("PKIID wasn't found") 112 } 113 return storedIdentity.fetchIdentity(), nil 114 } 115 116 // Sign signs a message, returns a signed message on success 117 // or an error on failure 118 func (is *identityMapperImpl) Sign(msg []byte) ([]byte, error) { 119 return is.mcs.Sign(msg) 120 } 121 122 // Verify verifies a signed message 123 func (is *identityMapperImpl) Verify(vkID, signature, message []byte) error { 124 cert, err := is.Get(vkID) 125 if err != nil { 126 return err 127 } 128 return is.mcs.Verify(cert, signature, message) 129 } 130 131 // GetPKIidOfCert returns the PKI-ID of a certificate 132 func (is *identityMapperImpl) GetPKIidOfCert(identity api.PeerIdentityType) common.PKIidType { 133 return is.mcs.GetPKIidOfCert(identity) 134 } 135 136 // ListInvalidIdentities returns a list of PKI-IDs that their corresponding 137 // peer identities have been revoked, expired or haven't been used 138 // for a long time 139 func (is *identityMapperImpl) ListInvalidIdentities(isSuspected api.PeerSuspector) []common.PKIidType { 140 revokedIds := is.validateIdentities(isSuspected) 141 if len(revokedIds) == 0 { 142 return nil 143 } 144 is.Lock() 145 defer is.Unlock() 146 for _, pkiID := range revokedIds { 147 delete(is.pkiID2Cert, string(pkiID)) 148 } 149 return revokedIds 150 } 151 152 // validateIdentities returns a list of identities that have been revoked, expired or haven't been 153 // used for a long time 154 func (is *identityMapperImpl) validateIdentities(isSuspected api.PeerSuspector) []common.PKIidType { 155 now := time.Now() 156 is.RLock() 157 defer is.RUnlock() 158 var revokedIds []common.PKIidType 159 for pkiID, storedIdentity := range is.pkiID2Cert { 160 if storedIdentity.fetchLastAccessTime().Add(identityUsageThreshold).Before(now) { 161 revokedIds = append(revokedIds, common.PKIidType(pkiID)) 162 continue 163 } 164 if !isSuspected(storedIdentity.fetchIdentity()) { 165 continue 166 } 167 if err := is.mcs.ValidateIdentity(storedIdentity.fetchIdentity()); err != nil { 168 revokedIds = append(revokedIds, common.PKIidType(pkiID)) 169 } 170 } 171 return revokedIds 172 } 173 174 type storedIdentity struct { 175 lastAccessTime int64 176 peerIdentity api.PeerIdentityType 177 } 178 179 func newStoredIdentity(identity api.PeerIdentityType) *storedIdentity { 180 return &storedIdentity{ 181 lastAccessTime: time.Now().UnixNano(), 182 peerIdentity: identity, 183 } 184 } 185 186 func (si *storedIdentity) fetchIdentity() api.PeerIdentityType { 187 atomic.StoreInt64(&si.lastAccessTime, time.Now().UnixNano()) 188 return si.peerIdentity 189 } 190 191 func (si *storedIdentity) fetchLastAccessTime() time.Time { 192 return time.Unix(0, atomic.LoadInt64(&si.lastAccessTime)) 193 }