Implement CA certificate information handling

Change the behaviour of the client to use the new CAInfoCommand support in
cacert-gosigner.

The client has a new mechanism to generate new commands as reaction to
received responses. This functionality is used to retrieve CA certificate
information when certificates previously unknown to the client appear
and to trigger CRL retrieval for new certificates.

New CA certificates announced by the signer are detected and information is
retrieved. The retrieved CA certificate is stored alongside the CRL files
in a configurable directory (defaults to "public" in the working directory
of the signerclient process).
main
Jan Dittberner 1 year ago
parent 199f0ee0c0
commit da24ae70b6

2
.gitignore vendored

@ -1,8 +1,8 @@
*Pty *Pty
/.idea/ /.idea/
/config.yaml /config.yaml
/crls/
/dist/ /dist/
/public/
/signerclient /signerclient
go.work go.work
go.work.sum go.work.sum

@ -3,7 +3,7 @@ module git.cacert.org/cacert-gosignerclient
go 1.19 go 1.19
require ( require (
git.cacert.org/cacert-gosigner v0.0.0-20221202080952-37d3b1e02146 git.cacert.org/cacert-gosigner v0.0.0-20221203104439-bc81ab84cb4a
github.com/balacode/go-delta v0.1.0 github.com/balacode/go-delta v0.1.0
github.com/shamaton/msgpackgen v0.3.0 github.com/shamaton/msgpackgen v0.3.0
github.com/sirupsen/logrus v1.9.0 github.com/sirupsen/logrus v1.9.0

@ -1,5 +1,11 @@
git.cacert.org/cacert-gosigner v0.0.0-20221202080952-37d3b1e02146 h1:vbm3fIRxNKD4jahqVnIvvU7jc57JfHz5KijalJFlHJ4= git.cacert.org/cacert-gosigner v0.0.0-20221202080952-37d3b1e02146 h1:vbm3fIRxNKD4jahqVnIvvU7jc57JfHz5KijalJFlHJ4=
git.cacert.org/cacert-gosigner v0.0.0-20221202080952-37d3b1e02146/go.mod h1:OGIB5wLUhJiBhTzSXReOhGxuy7sT5VvyOyT8Ux8EGyw= git.cacert.org/cacert-gosigner v0.0.0-20221202080952-37d3b1e02146/go.mod h1:OGIB5wLUhJiBhTzSXReOhGxuy7sT5VvyOyT8Ux8EGyw=
git.cacert.org/cacert-gosigner v0.0.0-20221202122810-6f8ac9818cd1 h1:HRtgcV6tRM+jN8NxPx7DkuwdH2prZOTdydMBCFg/CWM=
git.cacert.org/cacert-gosigner v0.0.0-20221202122810-6f8ac9818cd1/go.mod h1:OGIB5wLUhJiBhTzSXReOhGxuy7sT5VvyOyT8Ux8EGyw=
git.cacert.org/cacert-gosigner v0.0.0-20221202173159-afe7d23c9b6f h1:VcIwyogvdmYDpDwE7U0+S2P+xU5zwquppAVp2q4eI9k=
git.cacert.org/cacert-gosigner v0.0.0-20221202173159-afe7d23c9b6f/go.mod h1:OGIB5wLUhJiBhTzSXReOhGxuy7sT5VvyOyT8Ux8EGyw=
git.cacert.org/cacert-gosigner v0.0.0-20221203104439-bc81ab84cb4a h1:yX3lhEoBQkUKu23xggAzAeYWuziCkRYktSjsAOfNGHY=
git.cacert.org/cacert-gosigner v0.0.0-20221203104439-bc81ab84cb4a/go.mod h1:OGIB5wLUhJiBhTzSXReOhGxuy7sT5VvyOyT8Ux8EGyw=
github.com/balacode/go-delta v0.1.0 h1:pwz4CMn06P2bIaIfAx3GSabMPwJp/Ww4if+7SgPYa3I= 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/go-delta v0.1.0/go.mod h1:wLNrwTI3lHbPBvnLzqbHmA7HVVlm1u22XLvhbeA6t3o=
github.com/balacode/zr v1.0.0/go.mod h1:pLeSAL3DhZ9L0JuiRkUtIX3mLOCtzBLnDhfmykbSmkE= github.com/balacode/zr v1.0.0/go.mod h1:pLeSAL3DhZ9L0JuiRkUtIX3mLOCtzBLnDhfmykbSmkE=

@ -20,6 +20,7 @@ package client
import ( import (
"context" "context"
"crypto/x509" "crypto/x509"
"encoding/pem"
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
@ -33,6 +34,7 @@ import (
"git.cacert.org/cacert-gosigner/pkg/messages" "git.cacert.org/cacert-gosigner/pkg/messages"
"git.cacert.org/cacert-gosigner/pkg/protocol" "git.cacert.org/cacert-gosigner/pkg/protocol"
"git.cacert.org/cacert-gosignerclient/internal/command"
"git.cacert.org/cacert-gosignerclient/internal/config" "git.cacert.org/cacert-gosignerclient/internal/config"
) )
@ -49,30 +51,43 @@ type Profile struct {
} }
type CertInfo struct { type CertInfo struct {
Name string Name string
FetchCRL bool FetchCert bool
FetchCRL bool
LastKnownCRL *big.Int
Certificate *x509.Certificate
Profiles map[string]*Profile
} }
type SignerInfo struct { type SignerInfo struct {
SignerHealth bool SignerHealth bool
SignerVersion string SignerVersion string
CACertificates []CertInfo CACertificates []string
UsableProfiles map[string][]Profile }
func (i *SignerInfo) containsCA(caName string) bool {
for _, name := range i.CACertificates {
if name == caName {
return true
}
}
return false
} }
type Client struct { type Client struct {
port *serial.Port port *serial.Port
logger *logrus.Logger logger *logrus.Logger
framer protocol.Framer framer protocol.Framer
in chan []byte in chan []byte
out chan []byte out chan []byte
commands chan *protocol.Command commands chan *protocol.Command
handler protocol.ClientHandler handler protocol.ClientHandler
config *config.ClientConfig config *config.ClientConfig
signerInfo *SignerInfo signerInfo *SignerInfo
callback chan interface{} knownCertificates map[string]*CertInfo
callback chan interface{}
sync.Mutex sync.Mutex
lastKnownCRLS map[string]*big.Int
} }
func (c *Client) Run(ctx context.Context) error { func (c *Client) Run(ctx context.Context) error {
@ -158,63 +173,118 @@ func (c *Client) commandLoop(ctx context.Context) {
fetchCRLTimer := time.NewTimer(c.config.FetchCRLStart) fetchCRLTimer := time.NewTimer(c.config.FetchCRLStart)
for { for {
newCommands := make([]*protocol.Command, 0)
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
case callbackData := <-c.callback: case callbackData := <-c.callback:
err := c.handleCallback(callbackData) addCommands, err := c.handleCallback(callbackData)
if err != nil { if err != nil {
c.logger.WithError(err).Error("callback handling failed") c.logger.WithError(err).Error("callback handling failed")
} }
newCommands = append(newCommands, addCommands...)
case <-fetchCRLTimer.C: case <-fetchCRLTimer.C:
for _, crlInfo := range c.buildCRLInfo() { for _, crlInfo := range c.requiredCRLs() {
var lastKnown []byte newCommands = append(newCommands, command.FetchCRL(crlInfo.Name, crlInfo.LastKnown))
if crlInfo.LastKnown != nil {
lastKnown = crlInfo.LastKnown.Bytes()
}
c.commands <- &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdFetchCRL),
Command: &messages.FetchCRLCommand{
IssuerID: crlInfo.Name,
LastKnownID: lastKnown,
},
}
} }
fetchCRLTimer.Reset(c.config.FetchCRLInterval) fetchCRLTimer.Reset(c.config.FetchCRLInterval)
case <-healthTimer.C: case <-healthTimer.C:
c.commands <- &protocol.Command{ newCommands = append(newCommands, command.Health())
Announce: messages.BuildCommandAnnounce(messages.CmdHealth),
Command: &messages.HealthCommand{},
}
healthTimer.Reset(c.config.HealthInterval) healthTimer.Reset(c.config.HealthInterval)
} }
for _, nextCommand := range newCommands {
select {
case <-ctx.Done():
return
case c.commands <- nextCommand:
c.logger.WithField("command", nextCommand.Announce).Trace("sent command")
}
}
} }
} }
func (c *Client) handleCallback(data interface{}) error { func (c *Client) handleCallback(data interface{}) ([]*protocol.Command, error) {
switch d := data.(type) { switch d := data.(type) {
case SignerInfo: case SignerInfo:
c.updateSignerInfo(d) return c.updateSignerInfo(d)
case *messages.CAInfoResponse:
return c.updateCAInformation(d)
case *messages.FetchCRLResponse: case *messages.FetchCRLResponse:
c.updateCRL(d) return c.updateCRL(d)
default: default:
return fmt.Errorf("unknown callback data of type %T", data) return nil, fmt.Errorf("unknown callback data of type %T", data)
} }
}
return nil func (c *Client) updateSignerInfo(signerInfo SignerInfo) ([]*protocol.Command, error) {
c.logger.Debug("update signer info")
c.Lock()
c.signerInfo = &signerInfo
c.Unlock()
c.learnNewCACertificates()
c.forgetRemovedCACertificates()
newCommands := make([]*protocol.Command, 0)
for _, caName := range c.requiredCertificateInfo() {
newCommands = append(newCommands, command.CAInfo(caName))
}
return newCommands, nil
} }
func (c *Client) updateSignerInfo(signerInfo SignerInfo) { func (c *Client) updateCAInformation(d *messages.CAInfoResponse) ([]*protocol.Command, error) {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
c.logger.Debug("update signer info") caInfo, ok := c.knownCertificates[d.Name]
if !ok {
c.logger.WithField("certificate", d.Name).Warn("unknown CA certificate")
c.signerInfo = &signerInfo return nil, nil
}
cert, err := x509.ParseCertificate(d.Certificate)
if err != nil {
return nil, fmt.Errorf("could not parse CA certificate for %s: %w", d.Name, err)
}
if !cert.IsCA {
return nil, fmt.Errorf("certificate for %s is not a CA certificate", d.Name)
}
err = c.writeCertificate(caInfo.Name, d.Certificate)
if err != nil {
c.logger.WithError(err).WithField("certificate", d.Name).Warn("could not write CA certificate files")
}
caInfo.Certificate = cert
caInfo.FetchCert = false
caInfo.Profiles = make(map[string]*Profile)
for _, p := range d.Profiles {
caInfo.Profiles[p.Name] = &Profile{
Name: p.Name,
UseFor: p.UseFor.String(),
}
}
if len(cert.CRLDistributionPoints) == 0 {
caInfo.FetchCRL = false
return nil, nil
}
return []*protocol.Command{command.FetchCRL(caInfo.Name, c.lastKnownCRL(caInfo))}, nil
} }
type CRLInfo struct { type CRLInfo struct {
@ -222,43 +292,63 @@ type CRLInfo struct {
LastKnown *big.Int LastKnown *big.Int
} }
func (c *Client) buildCRLInfo() []CRLInfo { func (c *Client) requiredCRLs() []CRLInfo {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
if c.signerInfo == nil { if c.knownCertificates == nil {
c.logger.Warn("no signer info available") c.logger.Warn("no certificates known")
return nil return nil
} }
infos := make([]CRLInfo, 0) infos := make([]CRLInfo, 0)
for _, caInfo := range c.signerInfo.CACertificates { for _, caInfo := range c.knownCertificates {
if caInfo.FetchCRL { if caInfo.FetchCRL {
lastKnown := c.lastKnownCRL(caInfo.Name) infos = append(infos, CRLInfo{Name: caInfo.Name, LastKnown: c.lastKnownCRL(caInfo)})
}
}
return infos
}
func (c *Client) requiredCertificateInfo() []string {
c.Lock()
defer c.Unlock()
if c.knownCertificates == nil {
c.logger.Warn("no certificates known")
return nil
}
infos := make([]string, 0)
infos = append(infos, CRLInfo{Name: caInfo.Name, LastKnown: lastKnown}) for _, caInfo := range c.knownCertificates {
if caInfo.FetchCert {
infos = append(infos, caInfo.Name)
} }
} }
return infos return infos
} }
func (c *Client) lastKnownCRL(caName string) *big.Int { func (c *Client) lastKnownCRL(caInfo *CertInfo) *big.Int {
caName := caInfo.Name
crlFileName := c.buildCRLFileName(caName) crlFileName := c.buildCRLFileName(caName)
_, err := os.Stat(crlFileName) _, err := os.Stat(crlFileName)
if err != nil { if err != nil {
c.logger.WithField("crl", crlFileName).Debug("CRL file does not exist") c.logger.WithField("crl", crlFileName).Debug("CRL file does not exist")
delete(c.lastKnownCRLS, caName)
return nil return nil
} }
lastKnown, ok := c.lastKnownCRLS[caName] lastKnown := caInfo.LastKnownCRL
if !ok {
if lastKnown == nil {
derData, err := os.ReadFile(crlFileName) derData, err := os.ReadFile(crlFileName)
if err != nil { if err != nil {
c.logger.WithError(err).WithField("crl", crlFileName).Error("could not read CRL data") c.logger.WithError(err).WithField("crl", crlFileName).Error("could not read CRL data")
@ -274,27 +364,27 @@ func (c *Client) lastKnownCRL(caName string) *big.Int {
} }
lastKnown = crl.Number lastKnown = crl.Number
c.lastKnownCRLS[caName] = lastKnown
} }
return lastKnown return lastKnown
} }
func (c *Client) buildCRLFileName(caName string) string { func (c *Client) updateCRL(d *messages.FetchCRLResponse) ([]*protocol.Command, error) {
return path.Join(c.config.CRLDirectory, fmt.Sprintf("%s.crl", caName))
}
func (c *Client) updateCRL(d *messages.FetchCRLResponse) {
var ( var (
der []byte
crlNumber *big.Int crlNumber *big.Int
der []byte
err error
) )
caInfo, ok := c.knownCertificates[d.IssuerID]
if !ok {
c.logger.WithField("certificate", d.IssuerID).Warn("unknown CA certificate")
}
if d.UnChanged { if d.UnChanged {
c.logger.WithField("issuer", d.IssuerID).Debug("CRL did not change") c.logger.WithField("issuer", d.IssuerID).Debug("CRL did not change")
return return nil, nil
} }
if !d.IsDelta { if !d.IsDelta {
@ -304,29 +394,25 @@ func (c *Client) updateCRL(d *messages.FetchCRLResponse) {
if err != nil { if err != nil {
c.logger.WithError(err).Error("CRL from signer could not be parsed") c.logger.WithError(err).Error("CRL from signer could not be parsed")
return return nil, nil
} }
crlNumber = list.Number crlNumber = list.Number
} else { } else {
crlFileName := c.buildCRLFileName(d.IssuerID) crlFileName := c.buildCRLFileName(d.IssuerID)
der, err := c.patchCRL(crlFileName, d.CRLData) der, err = c.patchCRL(crlFileName, d.CRLData)
if err != nil { if err != nil {
c.logger.WithError(err).Error("CRL patching failed") c.logger.WithError(err).Error("CRL patching failed")
delete(c.lastKnownCRLS, d.IssuerID) return nil, nil
return
} }
list, err := x509.ParseRevocationList(der) list, err := x509.ParseRevocationList(der)
if err != nil { if err != nil {
c.logger.WithError(err).Error("could not parse patched CRL") c.logger.WithError(err).Error("could not parse patched CRL")
delete(c.lastKnownCRLS, d.IssuerID) return nil, nil
return
} }
crlNumber = list.Number crlNumber = list.Number
@ -335,17 +421,57 @@ func (c *Client) updateCRL(d *messages.FetchCRLResponse) {
if err := c.writeCRL(d.IssuerID, der); err != nil { if err := c.writeCRL(d.IssuerID, der); err != nil {
c.logger.WithError(err).Error("could not store CRL") c.logger.WithError(err).Error("could not store CRL")
delete(c.lastKnownCRLS, d.IssuerID) caInfo.LastKnownCRL = nil
return nil, nil
}
caInfo.LastKnownCRL = crlNumber
return nil, nil
}
func (c *Client) buildCRLFileName(caName string) string {
return path.Join(c.config.PublicDataDirectory, fmt.Sprintf("%s.crl", caName))
}
return func (c *Client) buildCertificateFileName(caName string, certFormat string) string {
return path.Join(c.config.PublicDataDirectory, fmt.Sprintf("%s.%s", caName, certFormat))
}
func (c *Client) ensurePublicDataDirectory() error {
if err := os.MkdirAll(c.config.PublicDataDirectory, worldReadableDirPerm); err != nil {
return fmt.Errorf("could not create public CA data directory %s: %w", c.config.PublicDataDirectory, err)
} }
c.lastKnownCRLS[d.IssuerID] = crlNumber return nil
}
func (c *Client) writeCertificate(caName string, derBytes []byte) error {
if err := c.ensurePublicDataDirectory(); err != nil {
return err
}
if err := os.WriteFile(
c.buildCertificateFileName(caName, "crt"), derBytes, worldReadableFilePerm,
); err != nil {
c.logger.WithError(err).Error("could not write DER encoded certificate file")
}
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err := os.WriteFile(
c.buildCertificateFileName(caName, "pem"), pemBytes, worldReadableFilePerm,
); err != nil {
c.logger.WithError(err).Error("could not write PEM encoded certificate file")
}
return nil
} }
func (c *Client) writeCRL(caName string, crlBytes []byte) error { func (c *Client) writeCRL(caName string, crlBytes []byte) error {
if err := os.MkdirAll(c.config.CRLDirectory, worldReadableDirPerm); err != nil { if err := c.ensurePublicDataDirectory(); err != nil {
return fmt.Errorf("could not create CRL directory %s: %w", c.config.CRLDirectory, err) return err
} }
if err := os.WriteFile(c.buildCRLFileName(caName), crlBytes, worldReadableFilePerm); err != nil { if err := os.WriteFile(c.buildCRLFileName(caName), crlBytes, worldReadableFilePerm); err != nil {
@ -374,6 +500,38 @@ func (c *Client) patchCRL(crlFileName string, diff []byte) ([]byte, error) {
return der, nil return der, nil
} }
func (c *Client) learnNewCACertificates() {
c.Lock()
defer c.Unlock()
for _, caName := range c.signerInfo.CACertificates {
if _, ok := c.knownCertificates[caName]; ok {
continue
}
c.knownCertificates[caName] = &CertInfo{
Name: caName,
FetchCert: true,
FetchCRL: true,
}
}
}
func (c *Client) forgetRemovedCACertificates() {
c.Lock()
defer c.Unlock()
for knownCA := range c.knownCertificates {
if c.signerInfo.containsCA(knownCA) {
continue
}
c.logger.WithField("certificate", knownCA).Warn("signer did not send status for certificate")
delete(c.knownCertificates, knownCA)
}
}
func New( func New(
cfg *config.ClientConfig, cfg *config.ClientConfig,
logger *logrus.Logger, logger *logrus.Logger,
@ -387,15 +545,15 @@ func New(
} }
client := &Client{ client := &Client{
logger: logger, logger: logger,
framer: cobsFramer, framer: cobsFramer,
in: make(chan []byte), in: make(chan []byte),
out: make(chan []byte), out: make(chan []byte),
commands: commands, commands: commands,
handler: handler, handler: handler,
config: cfg, config: cfg,
callback: callback, callback: callback,
lastKnownCRLS: make(map[string]*big.Int), knownCertificates: make(map[string]*CertInfo),
} }
err = client.setupConnection(&serial.Config{ err = client.setupConnection(&serial.Config{

@ -0,0 +1,55 @@
/*
Copyright 2022 CAcert Inc.
SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package command
import (
"math/big"
"git.cacert.org/cacert-gosigner/pkg/messages"
"git.cacert.org/cacert-gosigner/pkg/protocol"
)
func CAInfo(caName string) *protocol.Command {
return &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdCAInfo),
Command: &messages.CAInfoCommand{Name: caName},
}
}
func FetchCRL(caName string, crlNumber *big.Int) *protocol.Command {
var lastKnown []byte
if crlNumber != nil {
lastKnown = crlNumber.Bytes()
}
return &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdFetchCRL),
Command: &messages.FetchCRLCommand{
IssuerID: caName,
LastKnownID: lastKnown,
},
}
}
func Health() *protocol.Command {
return &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdHealth),
Command: &messages.HealthCommand{},
}
}

@ -31,10 +31,10 @@ const (
defaultHealthInterval = 30 * time.Second defaultHealthInterval = 30 * time.Second
defaultHealthStart = 2 * time.Second defaultHealthStart = 2 * time.Second
defaultFetchCRLInterval = 5 * time.Minute defaultFetchCRLInterval = 5 * time.Minute
defaultFetchCRLStart = 5 * time.Second defaultFetchCRLStart = 5 * time.Minute
defaultResponseAnnounceTimeout = 30 * time.Second defaultResponseAnnounceTimeout = 30 * time.Second
defaultResponseDataTimeout = 2 * time.Second defaultResponseDataTimeout = 2 * time.Second
defaultCRLDirectory = "crls" defaultFilesDirectory = "public"
) )
type SettingsError struct { type SettingsError struct {
@ -59,7 +59,7 @@ type ClientConfig struct {
FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"` FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"`
ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"` ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"`
ResponseDataTimeout time.Duration `yaml:"response-data-timeout"` ResponseDataTimeout time.Duration `yaml:"response-data-timeout"`
CRLDirectory string `yaml:"crl-directory"` PublicDataDirectory string `yaml:"public-data-directory"`
} }
func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error { func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error {
@ -71,7 +71,7 @@ func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error {
FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"` FetchCRLInterval time.Duration `yaml:"fetch-crl-interval"`
ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"` ResponseAnnounceTimeout time.Duration `yaml:"response-announce-timeout"`
ResponseDataTimeout time.Duration `yaml:"response-data-timeout"` ResponseDataTimeout time.Duration `yaml:"response-data-timeout"`
CRLDirectory string `yaml:"crl-directory"` PublicDataDirectory string `yaml:"public-data-directory"`
}{} }{}
err := n.Decode(&data) err := n.Decode(&data)
@ -129,11 +129,11 @@ func (c *ClientConfig) UnmarshalYAML(n *yaml.Node) error {
c.ResponseDataTimeout = data.ResponseDataTimeout c.ResponseDataTimeout = data.ResponseDataTimeout
if data.CRLDirectory == "" { if data.PublicDataDirectory == "" {
data.CRLDirectory = defaultCRLDirectory data.PublicDataDirectory = defaultFilesDirectory
} }
c.CRLDirectory = data.CRLDirectory c.PublicDataDirectory = data.PublicDataDirectory
return nil return nil
} }

@ -112,6 +112,13 @@ func (s *SignerClientHandler) ResponseData(ctx context.Context, in chan []byte,
return fmt.Errorf("could not unmarshal health response data: %w", err) return fmt.Errorf("could not unmarshal health response data: %w", err)
} }
response.Response = &resp
case messages.RespCAInfo:
var resp messages.CAInfoResponse
if err := msgpack.Unmarshal(frame, &resp); err != nil {
return fmt.Errorf("could not unmarshal CA info response data: %w", err)
}
response.Response = &resp response.Response = &resp
case messages.RespFetchCRL: case messages.RespFetchCRL:
var resp messages.FetchCRLResponse var resp messages.FetchCRLResponse
@ -146,6 +153,8 @@ func (s *SignerClientHandler) HandleResponse(ctx context.Context, response *prot
s.logger.WithField("message", r.Message).Error("error from signer") s.logger.WithField("message", r.Message).Error("error from signer")
case *messages.HealthResponse: case *messages.HealthResponse:
s.handleHealthResponse(ctx, r) s.handleHealthResponse(ctx, r)
case *messages.CAInfoResponse:
s.handleCAInfoResponse(ctx, r)
case *messages.FetchCRLResponse: case *messages.FetchCRLResponse:
s.handleFetchCRLResponse(ctx, r) s.handleFetchCRLResponse(ctx, r)
default: default:
@ -173,38 +182,19 @@ func (s *SignerClientHandler) handleHealthResponse(ctx context.Context, r *messa
switch item.Source { switch item.Source {
case "HSM": case "HSM":
signerInfo.CACertificates = make([]client.CertInfo, 0) signerInfo.CACertificates = make([]string, 0)
signerInfo.UsableProfiles = make(map[string][]client.Profile)
for certName, value := range item.MoreInfo { for certName, status := range item.MoreInfo {
certInfo, err := messages.ParseCertificateInfo(value) if status == string(messages.CertStatusOk) {
if err != nil { signerInfo.CACertificates = append(signerInfo.CACertificates, certName)
s.logger.WithError(err).Error("could not parse certificate information")
break continue
} }
s.logger.WithFields(map[string]interface{}{ s.logger.WithFields(map[string]interface{}{
"certificate": certName, "certificate": certName,
"signing": certInfo.Signing, "status": status,
"profiles": certInfo.Profiles, }).Warn("certificate has issues")
"status": certInfo.Status,
"valid-until": certInfo.ValidUntil,
}).Trace("certificate info")
signerInfo.CACertificates = append(
signerInfo.CACertificates,
client.CertInfo{Name: certName, FetchCRL: certInfo.Signing},
)
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: default:
s.logger.WithField("source", item.Source).Warn("unhandled health source") s.logger.WithField("source", item.Source).Warn("unhandled health source")
@ -219,6 +209,15 @@ func (s *SignerClientHandler) handleHealthResponse(ctx context.Context, r *messa
} }
} }
func (s *SignerClientHandler) handleCAInfoResponse(ctx context.Context, r *messages.CAInfoResponse) {
select {
case <-ctx.Done():
return
case s.clientCallback <- r:
break
}
}
func (s *SignerClientHandler) handleFetchCRLResponse(ctx context.Context, r *messages.FetchCRLResponse) { func (s *SignerClientHandler) handleFetchCRLResponse(ctx context.Context, r *messages.FetchCRLResponse) {
select { select {
case <-ctx.Done(): case <-ctx.Done():

Loading…
Cancel
Save