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  }