diff --git a/.gitignore b/.gitignore index 6e30653..e572e68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ *Pty /.idea/ /config.yaml +/crls/ /dist/ -/signerclient \ No newline at end of file +/signerclient +go.work \ No newline at end of file diff --git a/cmd/signerclient/main.go b/cmd/signerclient/main.go index 5a72f4c..b06bc18 100644 --- a/cmd/signerclient/main.go +++ b/cmd/signerclient/main.go @@ -77,13 +77,14 @@ func main() { } commands := make(chan *protocol.Command) + callbacks := make(chan interface{}, client.CallBackBufferSize) - clientHandler, err := handler.New(clientConfig, logger, commands) + clientHandler, err := handler.New(clientConfig, logger, commands, callbacks) if err != nil { logger.WithError(err).Fatal("could not setup client handler") } - signerClient, err := client.New(clientConfig, logger, clientHandler, commands) + signerClient, err := client.New(clientConfig, logger, clientHandler, commands, callbacks) if err != nil { logger.WithError(err).Fatal("could not setup client") } diff --git a/go.mod b/go.mod index c9d3f82..1dcf5d5 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,10 @@ module git.cacert.org/cacert-gosignerclient -go 1.17 +go 1.19 require ( - git.cacert.org/cacert-gosigner v0.0.0-20221129191234-c92b0455db62 + git.cacert.org/cacert-gosigner v0.0.0-20221130175146-fffc65a540d5 + github.com/balacode/go-delta v0.1.0 github.com/shamaton/msgpackgen v0.3.0 github.com/sirupsen/logrus v1.9.0 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 @@ -11,6 +12,7 @@ require ( ) require ( + github.com/balacode/zr v1.0.0 // indirect github.com/dave/jennifer v1.4.1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/justincpresley/go-cobs v1.2.0 // indirect diff --git a/go.sum b/go.sum index b9bb768..6916a68 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,9 @@ -git.cacert.org/cacert-gosigner v0.0.0-20221129191234-c92b0455db62 h1:MKpVPTm+rOjVK1/XtEaeGvBp6hQj4FlWnuKl66xK5ls= -git.cacert.org/cacert-gosigner v0.0.0-20221129191234-c92b0455db62/go.mod h1:yFBRxW6BwOyiXGtHQH/Vpro4Dxd0oIl3tCIWg99nYGE= -github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= +git.cacert.org/cacert-gosigner v0.0.0-20221130175146-fffc65a540d5 h1:ot7ENgYQj4xcqodTe1V2aIjvGLn+NVVhPu9+6XMuMTk= +git.cacert.org/cacert-gosigner v0.0.0-20221130175146-fffc65a540d5/go.mod h1:mb8oBdxQ26GI3xT4b8B7hXYWGED9vvjPGxehmbicyc4= +github.com/balacode/go-delta v0.1.0 h1:pwz4CMn06P2bIaIfAx3GSabMPwJp/Ww4if+7SgPYa3I= +github.com/balacode/go-delta v0.1.0/go.mod h1:wLNrwTI3lHbPBvnLzqbHmA7HVVlm1u22XLvhbeA6t3o= +github.com/balacode/zr v1.0.0 h1:MCupkEoXvrnCljc4KddiDOhR04ZLUAACgtKuo3o+9vc= +github.com/balacode/zr v1.0.0/go.mod h1:pLeSAL3DhZ9L0JuiRkUtIX3mLOCtzBLnDhfmykbSmkE= github.com/dave/jennifer v1.4.1 h1:XyqG6cn5RQsTj3qlWQTKlRGAyrTcsk1kUmWdZBzRjDw= github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -10,10 +13,6 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/justincpresley/go-cobs v1.2.0 h1:dyWszWzXObEv8sxVMJTAIo9XT7HEM10vkAOZq2eVEsQ= github.com/justincpresley/go-cobs v1.2.0/go.mod h1:L0d+EbGirv6IzsXNzwULduI2/z3ijkkAmsAuPMpLfqA= -github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shamaton/msgpack/v2 v2.1.0 h1:9jJ2eGZw2Wa9KExPX3KaDDckVjgr4zhXGFCfWagUWqg= @@ -24,18 +23,14 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/client/client.go b/internal/client/client.go index 928b2dd..d5fbc31 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -19,9 +19,15 @@ package client import ( "context" + "crypto/x509" "fmt" + "math/big" + "os" + "path" + "sync" "time" + "github.com/balacode/go-delta" "github.com/sirupsen/logrus" "github.com/tarm/serial" @@ -30,15 +36,38 @@ import ( "git.cacert.org/cacert-gosignerclient/internal/config" ) +const CallBackBufferSize = 50 + +const ( + worldReadableDirPerm = 0o755 + worldReadableFilePerm = 0o644 +) + +type Profile struct { + Name string + UseFor string +} + +type SignerInfo struct { + SignerHealth bool + SignerVersion string + CACertificates []string + UsableProfiles map[string][]Profile +} + type Client struct { - port *serial.Port - logger *logrus.Logger - framer protocol.Framer - in chan []byte - out chan []byte - commands chan *protocol.Command - handler protocol.ClientHandler - config *config.ClientConfig + port *serial.Port + logger *logrus.Logger + framer protocol.Framer + in chan []byte + out chan []byte + commands chan *protocol.Command + handler protocol.ClientHandler + config *config.ClientConfig + signerInfo *SignerInfo + callback chan interface{} + sync.Mutex + lastKnownCRLS map[string]*big.Int } func (c *Client) Run(ctx context.Context) error { @@ -97,6 +126,11 @@ func (c *Client) setupConnection(serialConfig *serial.Config) error { c.port = s + err = c.port.Flush() + if err != nil { + c.logger.WithError(err).Warn("could not flush buffers of port: %w", err) + } + return nil } @@ -116,11 +150,40 @@ func (c *Client) Close() error { func (c *Client) commandLoop(ctx context.Context) { healthTimer := time.NewTimer(c.config.HealthStart) + fetchCRLTimer := time.NewTimer(c.config.FetchCRLStart) for { select { case <-ctx.Done(): return + case callbackData := <-c.callback: + err := c.handleCallback(callbackData) + if err != nil { + c.logger.WithError(err).Error("callback handling failed") + } + case <-fetchCRLTimer.C: + for _, crlInfo := range c.buildCRLInfo() { + announce, err := messages.BuildCommandAnnounce(messages.CmdFetchCRL) + if err != nil { + c.logger.WithError(err).Error("could not build fetch CRL command announce") + } + + var lastKnown []byte + + if crlInfo.LastKnown != nil { + lastKnown = crlInfo.LastKnown.Bytes() + } + + c.commands <- &protocol.Command{ + Announce: announce, + Command: &messages.FetchCRLCommand{ + IssuerID: crlInfo.Name, + LastKnownID: lastKnown, + }, + } + } + + fetchCRLTimer.Reset(c.config.FetchCRLInterval) case <-healthTimer.C: announce, err := messages.BuildCommandAnnounce(messages.CmdHealth) if err != nil { @@ -137,20 +200,200 @@ func (c *Client) commandLoop(ctx context.Context) { } } +func (c *Client) handleCallback(data interface{}) error { + switch d := data.(type) { + case SignerInfo: + c.updateSignerInfo(d) + case *messages.FetchCRLResponse: + c.updateCRL(d) + default: + return fmt.Errorf("unknown callback data of type %T", data) + } + + return nil +} + +func (c *Client) updateSignerInfo(signerInfo SignerInfo) { + c.Lock() + defer c.Unlock() + + c.logger.Debug("update signer info") + + c.signerInfo = &signerInfo +} + +type CRLInfo struct { + Name string + LastKnown *big.Int +} + +func (c *Client) buildCRLInfo() []CRLInfo { + c.Lock() + defer c.Unlock() + + if c.signerInfo == nil { + c.logger.Warn("no signer info available") + + return nil + } + + infos := make([]CRLInfo, len(c.signerInfo.CACertificates)) + + for i, caName := range c.signerInfo.CACertificates { + lastKnown := c.lastKnownCRL(caName) + + infos[i] = CRLInfo{Name: caName, LastKnown: lastKnown} + } + + return infos +} + +func (c *Client) lastKnownCRL(caName string) *big.Int { + crlFileName := c.buildCRLFileName(caName) + + _, err := os.Stat(crlFileName) + if err != nil { + c.logger.WithField("crl", crlFileName).Debug("CRL file does not exist") + + delete(c.lastKnownCRLS, caName) + + return nil + } + + lastKnown, ok := c.lastKnownCRLS[caName] + if !ok { + derData, err := os.ReadFile(crlFileName) + if err != nil { + c.logger.WithError(err).WithField("crl", crlFileName).Error("could not read CRL data") + + return nil + } + + crl, err := x509.ParseRevocationList(derData) + if err != nil { + c.logger.WithError(err).WithField("crl", crlFileName).Error("could not parse CRL data") + + return nil + } + + lastKnown = crl.Number + + c.lastKnownCRLS[caName] = lastKnown + } + + return lastKnown +} + +func (c *Client) buildCRLFileName(caName string) string { + return path.Join(c.config.CRLDirectory, fmt.Sprintf("%s.crl", caName)) +} + +func (c *Client) updateCRL(d *messages.FetchCRLResponse) { + var ( + der []byte + crlNumber *big.Int + ) + + if d.UnChanged { + c.logger.WithField("issuer", d.IssuerID).Debug("CRL did not change") + + return + } + + if !d.IsDelta { + der = d.CRLData + + list, err := x509.ParseRevocationList(der) + if err != nil { + c.logger.WithError(err).Error("CRL from signer could not be parsed") + + return + } + + crlNumber = list.Number + } else { + crlFileName := c.buildCRLFileName(d.IssuerID) + + der, err := c.patchCRL(crlFileName, d.CRLData) + if err != nil { + c.logger.WithError(err).Error("CRL patching failed") + + delete(c.lastKnownCRLS, d.IssuerID) + + return + } + + list, err := x509.ParseRevocationList(der) + if err != nil { + c.logger.WithError(err).Error("could not parse patched CRL") + + delete(c.lastKnownCRLS, d.IssuerID) + + return + } + + crlNumber = list.Number + } + + if err := c.writeCRL(d.IssuerID, der); err != nil { + c.logger.WithError(err).Error("could not store CRL") + + delete(c.lastKnownCRLS, d.IssuerID) + + return + } + + c.lastKnownCRLS[d.IssuerID] = crlNumber +} + +func (c *Client) writeCRL(caName string, crlBytes []byte) error { + if err := os.MkdirAll(c.config.CRLDirectory, worldReadableDirPerm); err != nil { + return fmt.Errorf("could not create CRL directory %s: %w", c.config.CRLDirectory, err) + } + + if err := os.WriteFile(c.buildCRLFileName(caName), crlBytes, worldReadableFilePerm); err != nil { + c.logger.WithError(err).Error("could not write CRL file") + } + + return nil +} + +func (c *Client) patchCRL(crlFileName string, diff []byte) ([]byte, error) { + original, err := os.ReadFile(crlFileName) + if err != nil { + return nil, fmt.Errorf("could not read existing CRL %s: %w", crlFileName, err) + } + + patch, err := delta.Load(diff) + if err != nil { + return nil, fmt.Errorf("could not parse CRL delta: %w", err) + } + + der, err := patch.Apply(original) + if err != nil { + return nil, fmt.Errorf("could not apply CRL delta: %w", err) + } + + return der, nil +} + func New( cfg *config.ClientConfig, logger *logrus.Logger, handler protocol.ClientHandler, commands chan *protocol.Command, + callback chan interface{}, ) (*Client, error) { client := &Client{ - logger: logger, - framer: protocol.NewCOBSFramer(logger), - in: make(chan []byte), - out: make(chan []byte), - commands: commands, - handler: handler, - config: cfg, + logger: logger, + framer: protocol.NewCOBSFramer(logger), + in: make(chan []byte), + out: make(chan []byte), + commands: commands, + handler: handler, + config: cfg, + callback: callback, + lastKnownCRLS: make(map[string]*big.Int), } err := client.setupConnection(&serial.Config{ diff --git a/internal/config/config.go b/internal/config/config.go index a7c0daa..dd69f10 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -29,9 +29,12 @@ import ( const ( defaultSerialTimeout = 5 * time.Second defaultHealthInterval = 30 * time.Second - defaultHealthStart = 5 * time.Second + defaultHealthStart = 2 * time.Second + defaultFetchCRLInterval = 5 * time.Minute + defaultFetchCRLStart = 5 * time.Second defaultResponseAnnounceTimeout = 30 * time.Second defaultResponseDataTimeout = 2 * time.Second + defaultCRLDirectory = "crls" ) type SettingsError struct { @@ -52,8 +55,11 @@ type ClientConfig struct { Serial Serial `yaml:"serial"` HealthInterval time.Duration `yaml:"health-interval"` HealthStart time.Duration `yaml:"health-start"` + FetchCRLStart time.Duration `yaml:"fetch-crl-start"` + FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"` ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"` ResponseDataTimeout time.Duration `yaml:"response-data-timeout"` + CRLDirectory string `yaml:"crl-directory"` } func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error { @@ -61,8 +67,11 @@ func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error { Serial Serial `yaml:"serial"` HealthInterval time.Duration `yaml:"health-interval"` HealthStart time.Duration `yaml:"health-start"` + FetchCRLStart time.Duration `yaml:"fetch-crl-start"` + FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"` ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"` ResponseDataTimeout time.Duration `yaml:"response-data-timeout"` + CRLDirectory string `yaml:"crl-directory"` }{} err := n.Decode(&data) @@ -96,6 +105,18 @@ func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error { c.HealthStart = data.HealthStart + if data.FetchCRLInterval == 0 { + data.FetchCRLInterval = defaultFetchCRLInterval + } + + c.FetchCRLInterval = data.FetchCRLInterval + + if data.FetchCRLStart == 0 { + data.FetchCRLStart = defaultFetchCRLStart + } + + c.FetchCRLStart = data.FetchCRLStart + if data.ResponseAnnounceTimeout == 0 { data.ResponseAnnounceTimeout = defaultResponseAnnounceTimeout } @@ -108,6 +129,12 @@ func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error { c.ResponseDataTimeout = data.ResponseDataTimeout + if data.CRLDirectory == "" { + data.CRLDirectory = defaultCRLDirectory + } + + c.CRLDirectory = data.CRLDirectory + return nil } @@ -119,7 +146,7 @@ func New(clientConfigFile string) (*ClientConfig, error) { defer func() { _ = configFile.Close() }() - clientConfig, err := loadConfiguration(configFile) + clientConfig, err := LoadConfiguration(configFile) if err != nil { return nil, fmt.Errorf("could not load client configuration from %s: %w", clientConfigFile, err) } @@ -127,7 +154,7 @@ func New(clientConfigFile string) (*ClientConfig, error) { return clientConfig, nil } -func loadConfiguration(r io.Reader) (*ClientConfig, error) { +func LoadConfiguration(r io.Reader) (*ClientConfig, error) { var config *ClientConfig decoder := yaml.NewDecoder(r) diff --git a/internal/handler/handler.go b/internal/handler/handler.go index cce5707..ba97525 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -24,6 +24,8 @@ import ( "github.com/shamaton/msgpackgen/msgpack" "github.com/sirupsen/logrus" + "git.cacert.org/cacert-gosignerclient/internal/client" + "git.cacert.org/cacert-gosigner/pkg/messages" "git.cacert.org/cacert-gosigner/pkg/protocol" @@ -31,9 +33,10 @@ import ( ) type SignerClientHandler struct { - logger *logrus.Logger - commands chan *protocol.Command - config *config.ClientConfig + logger *logrus.Logger + commands chan *protocol.Command + config *config.ClientConfig + clientCallback chan interface{} } func (s *SignerClientHandler) Send(command *protocol.Command, out chan []byte) error { @@ -47,7 +50,7 @@ func (s *SignerClientHandler) Send(command *protocol.Command, out chan []byte) e return fmt.Errorf("could not marshal command annoucement: %w", err) } - s.logger.WithField("announcement", command.Announce).Info("write command announcement") + s.logger.WithField("announcement", command.Announce).Debug("write command announcement") s.logger.Trace("writing command announcement") @@ -58,7 +61,7 @@ func (s *SignerClientHandler) Send(command *protocol.Command, out chan []byte) e return fmt.Errorf("could not marshal command data: %w", err) } - s.logger.WithField("command", command.Command).Info("write command data") + s.logger.WithField("command", command.Command).Debug("write command data") out <- frame @@ -103,6 +106,13 @@ func (s *SignerClientHandler) ResponseData(in chan []byte, response *protocol.Re return fmt.Errorf("could not unmarshal fetch CRL response data: %w", err) } + response.Response = &resp + case messages.RespError: + var resp messages.ErrorResponse + if err := msgpack.Unmarshal(frame, &resp); err != nil { + return fmt.Errorf("could not unmarshal error response data: %w", err) + } + response.Response = &resp default: return fmt.Errorf("unhandled response code %s", response.Announce.Code) @@ -118,19 +128,90 @@ func (s *SignerClientHandler) HandleResponse(response *protocol.Response) error s.logger.WithField("response", response.Announce).Info("handled response") s.logger.WithField("response", response).Debug("full response") - // TODO: add real implementations + switch r := response.Response.(type) { + case *messages.ErrorResponse: + s.logger.WithField("message", r.Message).Error("error from signer") + case *messages.HealthResponse: + s.handleHealthResponse(r) + case *messages.FetchCRLResponse: + s.handleFetchCRLResponse(r) + default: + s.logger.WithField("response", response).Warnf("unhandled response of type %T", response.Response) + } return nil } +func (s *SignerClientHandler) handleHealthResponse(r *messages.HealthResponse) { + signerInfo := client.SignerInfo{} + + signerInfo.SignerHealth = r.Healthy + signerInfo.SignerVersion = r.Version + + if !r.Healthy { + // it might be a good idea to notify monitoring if the signer is not OK + s.logger.Error("signer is not healthy") + } + + for _, item := range r.Info { + if !item.Healthy { + s.logger.WithField("component", item.Source).Error("signer component is not healthy") + } + + switch item.Source { + case "HSM": + signerInfo.CACertificates = make([]string, 0) + signerInfo.UsableProfiles = make(map[string][]client.Profile) + + for certName, value := range item.MoreInfo { + certInfo, err := item.ParseCertificateInfo(value) + if err != nil { + s.logger.WithError(err).Error("could not parse certificate information") + + break + } + + s.logger.WithFields(map[string]interface{}{ + "certificate": certName, + "signing": certInfo.Signing, + "profiles": certInfo.Profiles, + "status": certInfo.Status, + "valid-until": certInfo.ValidUntil, + }).Trace("certificate info") + + signerInfo.CACertificates = append(signerInfo.CACertificates, certName) + + if certInfo.Signing { + for _, profile := range certInfo.Profiles { + signerInfo.UsableProfiles[certName] = append( + signerInfo.UsableProfiles[certName], + client.Profile{Name: profile.Name, UseFor: string(profile.UseFor)}, + ) + } + } + } + default: + s.logger.WithField("source", item.Source).Warn("unhandled health source") + } + } + + s.clientCallback <- signerInfo +} + +func (s *SignerClientHandler) handleFetchCRLResponse(r *messages.FetchCRLResponse) { + s.clientCallback <- r +} + func New( config *config.ClientConfig, logger *logrus.Logger, commands chan *protocol.Command, + clientCallback chan interface{}, ) (protocol.ClientHandler, error) { return &SignerClientHandler{ - logger: logger, - config: config, - commands: commands, + logger: logger, + config: config, + commands: commands, + clientCallback: clientCallback, }, nil }