func (m *Manager) ChainRevoked(chain []*x509.Certificate) bool {
	m.lock.RLock()
	defer m.lock.RUnlock()
	for _, c := range chain {
		if m.revokedSerials[string(c.SerialNumber.Bytes())] {
			return true
		}
	}
	return false
}
ChainRevoked returns true if any certificate in provided slice has been revoked.
package config
import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"errors"
	"fmt"
	"sync"
	"time"
	log "github.com/golang/glog"
	"github.com/golang/protobuf/proto"
	"github.com/google/fleetspeak/fleetspeak/src/client/config"
	"github.com/google/fleetspeak/fleetspeak/src/common"
	clpb "github.com/google/fleetspeak/fleetspeak/src/client/proto/fleetspeak_client"
	fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
)
type Manager struct {
	cfg *config.Configuration  
	cc  *clpb.CommunicatorConfig
	lock            sync.RWMutex  
	state           *clpb.ClientState
	id              common.ClientID
	revokedSerials  map[string]bool  
	dirty           bool             
	writebackPath   string
	runningServices map[string][]byte  
	syncTicker    *time.Ticker
	configChanges chan<- *fspb.ClientInfoData
	done          chan bool
}
func StartManager(cfg *config.Configuration, configChanges chan<- *fspb.ClientInfoData) (*Manager, error) {
	if cfg == nil {
		return nil, errors.New("configuration must be provided")
	}
	if cfg.PersistenceHandler == nil {
		log.Warning("PersistenceHandler not provided. Using NoopPersistenceHandler.")
		cfg.PersistenceHandler = config.NewNoopPersistenceHandler()
	}
	for _, l := range cfg.ClientLabels {
		if l.ServiceName != "client" || l.Label == "" {
			return nil, fmt.Errorf("invalid client label: %v", l)
		}
	}
	r := Manager{
		cfg: cfg,
		cc:  cfg.CommunicatorConfig,
		state:           &clpb.ClientState{},
		revokedSerials:  make(map[string]bool),
		dirty:           true,
		runningServices: make(map[string][]byte),
		configChanges: configChanges,
	}
	if r.cc == nil {
		r.cc = &clpb.CommunicatorConfig{}
	}
	var err error
	if r.state, err = cfg.PersistenceHandler.ReadState(); err != nil || r.state == nil {
		if err != nil {
			log.Errorf("initial load of writeback failed (continuing): %v", err)
		}
		r.state = &clpb.ClientState{}
	}
	r.AddRevokedSerials(r.state.RevokedCertSerials)
	r.AddRevokedSerials(cfg.RevokedCertSerials)
	if r.state.ClientKey == nil {
		if err := r.Rekey(); err != nil {
			return nil, fmt.Errorf("no key present, and %v", err)
		}
	} else {
		k, err := x509.ParseECPrivateKey(r.state.ClientKey)
		if err != nil {
			return nil, fmt.Errorf("unable to parse client key: %v", err)
		}
		r.id, err = common.MakeClientID(k.Public())
		if err != nil {
			return nil, fmt.Errorf("unable to create clientID: %v", err)
		}
		log.Infof("Using client id: %v", r.id)
	}
	if cc, err := cfg.PersistenceHandler.ReadCommunicatorConfig(); err == nil {
		if cc != nil {
			r.cc = cc
		}
	} else {
		log.Errorf("Error reading communicator config, ignoring: %v", err)
	}
	if err := r.Sync(); err != nil {
		return nil, fmt.Errorf("unable to write initial writeback: %v", err)
	}
	r.syncTicker = time.NewTicker(time.Minute)
	r.done = make(chan bool)
	go r.syncLoop()
	return &r, nil
}
func (m *Manager) Rekey() error {
	k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return fmt.Errorf("unable to generate new key: %v", err)
	}
	bytes, err := x509.MarshalECPrivateKey(k)
	if err != nil {
		return fmt.Errorf("unable to marshal new key: %v", err)
	}
	id, err := common.MakeClientID(k.Public())
	if err != nil {
		return fmt.Errorf("unable to create client id: %v", err)
	}
	m.lock.Lock()
	m.state.ClientKey = bytes
	m.id = id
	m.dirty = true
	m.lock.Unlock()
	log.Infof("Using new client id: %v", id)
	return nil
}
func (m *Manager) Sync() error {
	m.lock.RLock()
	d := m.dirty
	m.lock.RUnlock()
	if !d {
		return nil
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	if err := m.cfg.PersistenceHandler.WriteState(m.state); err != nil {
		return fmt.Errorf("Failed to sync state to writeback: %v", err)
	}
	m.dirty = false
	return nil
}
func (m *Manager) AddRevokedSerials(revoked [][]byte) {
	if len(revoked) == 0 {
		return
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	for _, serial := range revoked {
		ss := string(serial)
		if !m.revokedSerials[ss] {
			m.revokedSerials[ss] = true
			m.state.RevokedCertSerials = append(m.state.RevokedCertSerials, serial)
			m.dirty = true
		}
	}
}
func (m *Manager) Stop() {
	if m.syncTicker != nil {
		m.syncTicker.Stop()
		close(m.done)
	}
}
func (m *Manager) syncLoop() {
	for {
		select {
		case <-m.syncTicker.C:
			m.Sync()
		case <-m.done:
			return
		}
	}
}
func (m *Manager) ClientID() common.ClientID {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.id
}
func (m *Manager) RecordRunningService(name string, sig []byte) {
	m.lock.Lock()
	defer m.lock.Unlock()
	m.runningServices[name] = sig
	m.dirty = true
}
func (m *Manager) SequencingNonce() uint64 {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.state.SequencingNonce
}
func (m *Manager) SetSequencingNonce(n uint64) {
	m.lock.Lock()
	defer m.lock.Unlock()
	m.state.SequencingNonce = n
	m.dirty = true
}
func (m *Manager) SendConfigUpdate() {
	m.lock.RLock()
	defer m.lock.RUnlock()
	info := fspb.ClientInfoData{
		Labels: m.cfg.ClientLabels,
	}
	for s, sig := range m.runningServices {
		info.Services = append(info.Services,
			&fspb.ClientInfoData_ServiceID{
				Name:      s,
				Signature: sig,
			})
	}
	m.configChanges <- &info
}
func (m *Manager) CurrentState() *clpb.ClientState {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return proto.Clone(m.state).(*clpb.ClientState)
}
func (m *Manager) Configuration() *config.Configuration {
	return m.cfg
}
func (m *Manager) CommunicatorConfig() *clpb.CommunicatorConfig {
	return m.cc
}