Implement command type handling

This commit changes the wire protocol to split between command
announcement and command payload to allow proper typing of sent and
received msgpack messages.

CRL fetching has been implemented as second command after the existing
health check command.
This commit is contained in:
Jan Dittberner 2022-11-20 18:59:37 +01:00
parent 472091b374
commit 2de592d30c
13 changed files with 1258 additions and 214 deletions

9
.gitignore vendored
View file

@ -1,10 +1,11 @@
*.crt
*.pem
*.pub
.idea/
/.idea/
/ca-hierarchy.json
/clientsim
/config.yaml
/dist/
/repos/
/signer
/testPty
ca-hierarchy.json
config.yaml
dist/

View file

@ -20,6 +20,7 @@ limitations under the License.
package main
import (
"bytes"
"context"
"fmt"
"os"
@ -30,6 +31,8 @@ import (
"github.com/shamaton/msgpackgen/msgpack"
"github.com/sirupsen/logrus"
"git.cacert.org/cacert-gosigner/pkg/protocol"
"git.cacert.org/cacert-gosigner/pkg/messages"
)
@ -39,7 +42,7 @@ var cobsConfig = cobs.Config{SpecialByte: cobsDelimiter, Delimiter: true, Ending
func main() {
logger := logrus.New()
logger.SetOutput(os.Stdout)
logger.SetOutput(os.Stderr)
logger.SetLevel(logrus.InfoLevel)
sim := &clientSimulator{
@ -48,14 +51,14 @@ func main() {
err := sim.Run()
if err != nil {
logger.Errorf("simulator returned an error: %v", err)
logger.WithError(err).Error("simulator returned an error")
}
}
type clientSimulator struct {
logger *logrus.Logger
commands chan messages.Command
responses chan []byte
commands chan *protocol.Command
responses chan [][]byte
}
func (c *clientSimulator) writeTestCommands(ctx context.Context) error {
@ -63,6 +66,13 @@ func (c *clientSimulator) writeTestCommands(ctx context.Context) error {
const healthInterval = 10 * time.Second
time.Sleep(healthInterval)
c.commands <- &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdFetchCRL),
Command: &messages.FetchCRLCommand{IssuerID: "sub-ecc_person_2022"},
}
timer := time.NewTimer(healthInterval)
for {
@ -70,15 +80,17 @@ func (c *clientSimulator) writeTestCommands(ctx context.Context) error {
case <-ctx.Done():
_ = timer.Stop()
c.logger.Info("stopping health check loop")
return nil
case <-timer.C:
c.commands <- messages.Command{
Code: messages.CmdHealth,
TimeStamp: time.Now().UTC(),
c.commands <- &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdHealth),
Command: &messages.HealthCommand{},
}
timer.Reset(healthInterval)
}
timer.Reset(healthInterval)
}
}
@ -90,6 +102,18 @@ func (c *clientSimulator) handleInput(ctx context.Context) error {
buf := make([]byte, bufferSize)
type protocolState int8
const (
stAnn protocolState = iota
stResp
)
state := stAnn
var announce []byte
reading:
for {
select {
case <-ctx.Done():
@ -108,12 +132,26 @@ func (c *clientSimulator) handleInput(ctx context.Context) error {
data := buf[:count]
err = cobs.Verify(data, cobsConfig)
if err != nil {
return fmt.Errorf("frame verification failed: %w", err)
}
for _, frame := range bytes.SplitAfter(data, []byte{cobsConfig.SpecialByte}) {
if len(frame) == 0 {
continue reading
}
c.responses <- cobs.Decode(data, cobsConfig)
err = cobs.Verify(frame, cobsConfig)
if err != nil {
return fmt.Errorf("frame verification failed: %w", err)
}
if state == stAnn {
announce = cobs.Decode(frame, cobsConfig)
state = stResp
} else {
c.responses <- [][]byte{announce, cobs.Decode(frame, cobsConfig)}
state = stAnn
}
}
}
}
}
@ -122,75 +160,152 @@ func (c *clientSimulator) handleCommands(ctx context.Context) error {
for {
select {
case command := <-c.commands:
commandBytes, err := msgpack.Marshal(command)
if err != nil {
return fmt.Errorf("could not marshal command bytes: %w", err)
if err := writeCommandAnnouncement(command); err != nil {
return err
}
_, err = os.Stdout.Write(cobs.Encode(commandBytes, cobsConfig))
if err != nil {
return fmt.Errorf("write failed: %w", err)
if err := writeCommand(command); err != nil {
return err
}
responseBytes := <-c.responses
respData := <-c.responses
var response messages.Response
c.logger.WithField("respdata", respData).Trace("read response data")
err = msgpack.Unmarshal(responseBytes, &response)
if err != nil {
return fmt.Errorf("could not unmarshal msgpack data: %w", err)
response := &protocol.Response{}
if err := msgpack.Unmarshal(respData[0], &response.Announce); err != nil {
return fmt.Errorf("could not unmarshal response announcement: %w", err)
}
if err := c.handleResponse(response, respData[1]); err != nil {
return err
}
c.logger.Errorf("received response: %+v", response)
case <-ctx.Done():
return nil
}
}
}
func (c *clientSimulator) handleResponse(response *protocol.Response, respBytes []byte) error {
switch response.Announce.Code {
case messages.RespHealth:
data := messages.HealthResponse{}
if err := msgpack.Unmarshal(respBytes, &data); err != nil {
return fmt.Errorf("could not unmarshal health data: %w", err)
}
c.logger.WithField(
"announce",
response.Announce,
).WithField(
"data",
&data,
).Infof("received response")
case messages.RespFetchCRL:
data := messages.FetchCRLResponse{}
if err := msgpack.Unmarshal(respBytes, &data); err != nil {
return fmt.Errorf("could not unmarshal fetch CRL data: %w", err)
}
c.logger.WithField(
"announce",
response.Announce,
).WithField(
"data",
&data,
).Infof("received response")
case messages.RespError:
data := messages.ErrorResponse{}
if err := msgpack.Unmarshal(respBytes, &data); err != nil {
return fmt.Errorf("could not unmarshal error data: %w", err)
}
c.logger.WithField(
"announce",
response.Announce,
).WithField(
"data",
&data,
).Infof("received response")
default:
if err := msgpack.Unmarshal(respBytes, &response.Response); err != nil {
return fmt.Errorf("could not unmarshal response: %w", err)
}
c.logger.WithField("response", response).Infof("received response")
}
return nil
}
func writeCommandAnnouncement(command *protocol.Command) error {
cmdAnnounceBytes, err := msgpack.Marshal(&command.Announce)
if err != nil {
return fmt.Errorf("could not marshal command announcement bytes: %w", err)
}
if _, err = os.Stdout.Write(cobs.Encode(cmdAnnounceBytes, cobsConfig)); err != nil {
return fmt.Errorf("command announcement write failed: %w", err)
}
return nil
}
func writeCommand(command *protocol.Command) error {
cmdBytes, err := msgpack.Marshal(&command.Command)
if err != nil {
return fmt.Errorf("could not marshal command bytes: %w", err)
}
if _, err = os.Stdout.Write(cobs.Encode(cmdBytes, cobsConfig)); err != nil {
return fmt.Errorf("command write failed: %w", err)
}
return nil
}
func (c *clientSimulator) Run() error {
ctx, cancel := context.WithCancel(context.Background())
c.commands = make(chan messages.Command)
c.responses = make(chan []byte)
c.commands = make(chan *protocol.Command)
c.responses = make(chan [][]byte)
wg := sync.WaitGroup{}
wg.Add(2)
var inputError, commandError error
go func(inputErr error) {
_ = c.handleInput(ctx)
go func() {
if err := c.handleInput(ctx); err != nil {
c.logger.WithError(err).Error("input handling failed")
}
cancel()
wg.Done()
}(inputError)
}()
go func(commandErr error) {
_ = c.handleCommands(ctx)
go func() {
if err := c.handleCommands(ctx); err != nil {
c.logger.WithError(err).Error("command handling failed")
}
cancel()
wg.Done()
}(commandError)
}()
var result error
if err := c.writeTestCommands(ctx); err != nil {
c.logger.Errorf("test commands failed: %v", err)
c.logger.WithError(err).Error("test commands failed")
}
cancel()
wg.Wait()
if inputError != nil {
c.logger.Errorf("reading input failed: %v", inputError)
}
if commandError != nil {
c.logger.Errorf("sending commands failed: %v", commandError)
}
return result
}

View file

@ -19,10 +19,13 @@ package main
import (
"flag"
"fmt"
"os"
"github.com/sirupsen/logrus"
"git.cacert.org/cacert-gosigner/pkg/x509/revoking"
"git.cacert.org/cacert-gosigner/pkg/config"
"git.cacert.org/cacert-gosigner/pkg/health"
"git.cacert.org/cacert-gosigner/pkg/hsm"
@ -51,7 +54,7 @@ func main() {
logger.SetOutput(os.Stdout)
logger.SetLevel(logrus.InfoLevel)
logger.Infof("cacert-gosigner %s (%s) - built %s\n", version, commit, date)
logger.Infof("cacert-gosigner %s (%s) - built %s", version, commit, date)
flag.StringVar(&signerConfigFile, "config", defaultSignerConfigFile, "signer configuration file")
flag.BoolVar(&showVersion, "version", false, "show version")
@ -67,12 +70,12 @@ func main() {
parsedLevel, err := logrus.ParseLevel(logLevel)
if err != nil {
logger.Fatalf("could not parse log level: %v", err)
logger.WithError(err).Fatal("could not parse log level")
}
logger.SetLevel(parsedLevel)
caConfig := LoadConfig(signerConfigFile, logger)
caConfig := loadConfig(signerConfigFile, logger)
access := initializeHSM(caConfig, setupMode, verbose, logger)
@ -82,23 +85,77 @@ func main() {
healthHandler := health.New(version, access)
proto, err := protocol.New(logger, protocol.RegisterHealthHandler(healthHandler))
revokingRepositories, err := configureRepositories(caConfig)
if err != nil {
logger.Fatalf("could not setup protocol handler: %v", err)
logger.WithError(err).Fatal("could not setup revoking repositories")
}
fetchCRLHandler := revoking.NewFetchCRLHandler(revokingRepositories)
proto, err := protocol.New(
logger,
protocol.RegisterHealthHandler(healthHandler),
protocol.RegisterFetchCRLHandler(fetchCRLHandler),
)
if err != nil {
logger.WithError(err).Fatal("could not setup protocol handler")
}
serialHandler, err := seriallink.New(caConfig.GetSerial(), proto)
if err != nil {
logger.Fatalf("could not setup serial link handler: %v", err)
logger.WithError(err).Fatal("could not setup serial link handler")
}
defer func() { _ = serialHandler.Close() }()
if err = serialHandler.Run(); err != nil {
logger.Fatalf("error in serial handler: %v", err)
logger.WithError(err).Fatal("error in serial handler")
}
logger.Infof("setup complete, starting signer operation")
logger.Info("setup complete, starting signer operation")
}
func configureRepositories(
caConfig *config.SignerConfig,
) (map[string]*revoking.X509Revoking, error) {
var err error
result := make(map[string]*revoking.X509Revoking)
for _, name := range caConfig.RootCAs() {
result[fmt.Sprintf("root-%s", name)], err = buildX509Revoking(caConfig, name)
if err != nil {
return nil, err
}
}
for _, name := range caConfig.SubordinateCAs() {
result[fmt.Sprintf("sub-%s", name)], err = buildX509Revoking(caConfig, name)
if err != nil {
return nil, err
}
}
return result, nil
}
func buildX509Revoking(caConfig *config.SignerConfig, name string) (*revoking.X509Revoking, error) {
caDef, err := caConfig.GetCADefinition(name)
if err != nil {
return nil, fmt.Errorf("could not get CA definition for %s: %w", name, err)
}
repo, err := caConfig.Repository(name)
if err != nil {
return nil, fmt.Errorf("could not get repository for %s: %w", name, err)
}
return revoking.NewX509Revoking(
repo,
caDef.KeyInfo.CRLSignatureAlgorithm,
caDef.Certificate,
caDef.KeyPair,
), nil
}
func initializeHSM(caConfig *config.SignerConfig, setupMode, verbose bool, logger *logrus.Logger) *hsm.Access {
@ -118,21 +175,21 @@ func initializeHSM(caConfig *config.SignerConfig, setupMode, verbose bool, logge
access, err := hsm.NewAccess(logger, opts...)
if err != nil {
logger.Fatalf("could not setup HSM access: %v", err)
logger.WithError(err).Fatal("could not setup HSM access")
}
err = access.EnsureCAKeysAndCertificates()
if err != nil {
logger.Fatalf("could not ensure CA keys and certificates exist: %v", err)
logger.WithError(err).Fatal("could not ensure CA keys and certificates exist")
}
return access
}
func LoadConfig(signerConfigFile string, logger *logrus.Logger) *config.SignerConfig {
func loadConfig(signerConfigFile string, logger *logrus.Logger) *config.SignerConfig {
configFile, err := os.Open(signerConfigFile)
if err != nil {
logger.Fatalf("could not open signer configuration file %s: %v", signerConfigFile, err)
logger.WithError(err).Fatalf("could not open signer configuration file: %s", signerConfigFile)
}
caConfig, err := config.LoadConfiguration(configFile)

2
go.mod
View file

@ -6,6 +6,7 @@ require (
github.com/ThalesIgnite/crypto11 v1.2.5
github.com/justincpresley/go-cobs v1.2.0
github.com/shamaton/msgpackgen v0.3.0
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.0
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171
@ -19,7 +20,6 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/shamaton/msgpack/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
)

1
go.sum
View file

@ -32,7 +32,6 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUY
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
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=

View file

@ -25,12 +25,19 @@ import (
"errors"
"fmt"
"io"
"path"
"strings"
"time"
"gopkg.in/yaml.v3"
"git.cacert.org/cacert-gosigner/pkg/x509/openssl"
"git.cacert.org/cacert-gosigner/pkg/x509/revoking"
"git.cacert.org/cacert-gosigner/pkg/x509/signing"
)
const minRSABits = 2048
type Serial struct {
Device string
Baud int
@ -197,10 +204,16 @@ func (k *KeyStorage) UnmarshalYAML(n *yaml.Node) error {
return nil
}
type CARepository interface {
revoking.Repository
signing.Repository
}
type SignerConfig struct {
global *Settings `yaml:"Settings"`
caMap map[string]*CaCertificateEntry `yaml:"CAs"`
keyStorage map[string]*KeyStorage `yaml:"KeyStorage"`
global *Settings `yaml:"Settings"`
caMap map[string]*CaCertificateEntry `yaml:"CAs"`
keyStorage map[string]*KeyStorage `yaml:"KeyStorage"`
repositories map[string]CARepository
}
func (c *SignerConfig) GetCADefinition(label string) (*CaCertificateEntry, error) {
@ -321,6 +334,26 @@ func (c *SignerConfig) GetSerial() *Serial {
return c.global.Serial
}
func (c *SignerConfig) Repository(name string) (CARepository, error) {
var (
repo CARepository
ok bool
err error
)
repo, ok = c.repositories[name]
if !ok {
repo, err = openssl.NewFileRepository(path.Join("repos", name))
if err != nil {
return nil, fmt.Errorf("could not create repository for %s: %w", name, err)
}
c.repositories[name] = repo
}
return repo, nil
}
// LoadConfiguration reads YAML configuration from the given reader as a SignerConfig structure
func LoadConfiguration(r io.Reader) (*SignerConfig, error) {
config := struct {
@ -349,23 +382,26 @@ func LoadConfiguration(r io.Reader) (*SignerConfig, error) {
}
return &SignerConfig{
global: config.Global,
caMap: config.CAs,
keyStorage: config.KeyStorage,
global: config.Global,
caMap: config.CAs,
keyStorage: config.KeyStorage,
repositories: make(map[string]CARepository),
}, nil
}
type PrivateKeyInfo struct {
Algorithm x509.PublicKeyAlgorithm
EccCurve elliptic.Curve
RSABits int
Algorithm x509.PublicKeyAlgorithm
EccCurve elliptic.Curve
RSABits int
CRLSignatureAlgorithm x509.SignatureAlgorithm
}
func (p *PrivateKeyInfo) UnmarshalYAML(value *yaml.Node) error {
internalStructure := struct {
Algorithm string `yaml:"algorithm"`
EccCurve string `yaml:"ecc-curve,omitempty"`
RSABits *int `yaml:"rsa-bits,omitempty"`
Algorithm string `yaml:"algorithm"`
EccCurve string `yaml:"ecc-curve,omitempty"`
RSABits *int `yaml:"rsa-bits,omitempty"`
CRLSignatureAlgorithm string `yaml:"crl-signature-algorithm,omitempty"`
}{}
err := value.Decode(&internalStructure)
@ -382,6 +418,12 @@ func (p *PrivateKeyInfo) UnmarshalYAML(value *yaml.Node) error {
}
p.RSABits = *internalStructure.RSABits
if p.RSABits < minRSABits {
return fmt.Errorf("RSA keys must have a length of at least %d bits", minRSABits)
}
p.CRLSignatureAlgorithm = determineRSASignatureAlgorithm(internalStructure.CRLSignatureAlgorithm)
case "EC":
p.Algorithm = x509.ECDSA
@ -393,6 +435,8 @@ func (p *PrivateKeyInfo) UnmarshalYAML(value *yaml.Node) error {
if err != nil {
return err
}
p.CRLSignatureAlgorithm = determineECDSASignatureAlgorithm(internalStructure.CRLSignatureAlgorithm)
case "":
return errors.New("element 'algorithm' must be specified as 'EC' or 'RSA'")
default:
@ -405,6 +449,32 @@ func (p *PrivateKeyInfo) UnmarshalYAML(value *yaml.Node) error {
return nil
}
func determineRSASignatureAlgorithm(algorithm string) x509.SignatureAlgorithm {
switch strings.ToLower(algorithm) {
case "sha1withrsa", "sha1":
return x509.SHA1WithRSA
case "sha384withrsa", "sha384":
return x509.SHA384WithRSA
case "sha512withrsa", "sha512":
return x509.SHA512WithRSA
default:
return x509.SHA256WithRSA
}
}
func determineECDSASignatureAlgorithm(algorithm string) x509.SignatureAlgorithm {
switch strings.ToLower(algorithm) {
case "sha1withecdsa", "sha1":
return x509.ECDSAWithSHA1
case "sha384withecdsa", "sha384":
return x509.ECDSAWithSHA384
case "sha512withecdsa", "sha512":
return x509.ECDSAWithSHA512
default:
return x509.ECDSAWithSHA256
}
}
func (p *PrivateKeyInfo) MarshalYAML() (interface{}, error) {
internalStructure := struct {
Algorithm string `yaml:"algorithm"`

View file

@ -79,6 +79,8 @@ func (a *Access) Healthy() (*health.Info, error) {
healthy = false
moreInfo[infoKey] = checkFailed
continue
}
moreInfo[infoKey] = fmt.Sprintf("ok, valid until %s", cert.NotAfter.UTC().Format(time.RFC3339))
@ -92,6 +94,8 @@ func (a *Access) Healthy() (*health.Info, error) {
healthy = false
moreInfo[infoKey] = checkFailed
continue
}
def, err := a.signerConfig.GetCADefinition(ca)
@ -99,6 +103,8 @@ func (a *Access) Healthy() (*health.Info, error) {
healthy = false
moreInfo[infoKey] = checkFailed
continue
}
_, err = a.getKeyPair(ca, def.KeyInfo)
@ -106,6 +112,8 @@ func (a *Access) Healthy() (*health.Info, error) {
healthy = false
moreInfo[infoKey] = checkFailed
continue
}
moreInfo[infoKey] = fmt.Sprintf("ok, valid until %s", cert.NotAfter.UTC().Format(time.RFC3339))
@ -307,6 +315,8 @@ func (a *Access) GetSubordinateCACertificate(certLabel string) (*x509.Certificat
return nil, err
}
caCert.Certificate, caCert.KeyPair = certificate, keyPair
return certificate, nil
}

View file

@ -21,58 +21,82 @@ limitations under the License.
package messages
import (
"crypto/x509"
"encoding/pem"
"fmt"
"strings"
"time"
)
type CommandCode int
type CommandCode int8
const (
CmdHealth CommandCode = iota
CmdFetchCRL
)
var commandNames = map[CommandCode]string{
CmdHealth: "HEALTH",
CmdFetchCRL: "FETCH URL",
}
func (c CommandCode) String() string {
switch c {
case CmdHealth:
return "HEALTH"
default:
return fmt.Sprintf("unknown (%d)", int(c))
if name, ok := commandNames[c]; ok {
return name
}
return fmt.Sprintf("unknown %d", c)
}
type Command struct {
Code CommandCode `msgpack:"code"`
TimeStamp time.Time `msgpack:"created"`
Payload interface{} `msgpack:"payload"` // optional payload
}
type ResponseCode int
type ResponseCode int8
const (
RspError ResponseCode = -1
RspHealth ResponseCode = iota
RespError ResponseCode = -1
RespHealth ResponseCode = iota
RespFetchCRL
)
func (r ResponseCode) String() string {
switch r {
case RspError:
return "ERROR"
case RspHealth:
return "HEALTH"
default:
return fmt.Sprintf("unknown (%d)", int(r))
var responseNames = map[ResponseCode]string{
RespError: "ERROR",
RespHealth: "HEALTH",
RespFetchCRL: "FETCH CRL",
}
func (c ResponseCode) String() string {
if name, ok := responseNames[c]; ok {
return name
}
return fmt.Sprintf("unknown %d", c)
}
type Response struct {
Code ResponseCode `msgpack:"code"`
TimeStamp time.Time `msgpack:"created"`
Payload interface{} `msgpack:"payload"`
type CommandAnnounce struct {
Code CommandCode `msgpack:"code"`
Created time.Time `msgpack:"created"`
}
func (r *Response) String() string {
return fmt.Sprintf("[%s] at %s: %+v", r.Code, r.TimeStamp, r.Payload)
func (r *CommandAnnounce) String() string {
return fmt.Sprintf("CommandAnnounce[code=%s, created=%s]", r.Code, r.Created)
}
type ResponseAnnounce struct {
Code ResponseCode `msgpack:"code"`
Created time.Time `msgpack:"created"`
}
func (r *ResponseAnnounce) String() string {
return fmt.Sprintf("ResponseAnnounce[code=%s, created=%s]", r.Code, r.Created)
}
type FetchCRLCommand struct {
IssuerID string `msgpack:"issuer_id"`
LastKnownHash struct {
Algorithm string `msgpack:"algorithm"`
Value string `msgpack:"value"`
} `msgpack:"last_known_hash"` // optional last known hash in format
}
type HealthCommand struct {
}
type HealthInfo struct {
@ -97,10 +121,61 @@ func (i *HealthInfo) String() string {
type HealthResponse struct {
Version string `msgpack:"version"`
Healthy bool
Info []HealthInfo
Healthy bool `msgpack:"healthy"`
Info []*HealthInfo
}
func (h *HealthResponse) String() string {
builder := &strings.Builder{}
_, _ = fmt.Fprintf(builder, "signer version=%s, healthy=%v, health data:\n", h.Version, h.Healthy)
for _, info := range h.Info {
_, _ = fmt.Fprintf(builder, " - %s", info)
}
return builder.String()
}
type FetchCRLResponse struct {
IssuerID string `msgpack:"issuer_id"`
IsDelta bool `msgpack:"is_delta"`
CRLData []byte `msgpack:"crl_data"`
}
func (r *FetchCRLResponse) String() string {
builder := &strings.Builder{}
_, _ = fmt.Fprintf(builder, "issuer id=%s, delta CRL data=%v", r.IssuerID, r.IsDelta)
if r.IsDelta {
_, _ = fmt.Fprint(builder, ", delta CRL data not shown")
} else {
revlist, err := x509.ParseRevocationList(r.CRLData)
if err != nil {
_, _ = fmt.Fprintf(builder, ", could not parse CRL: %s", err.Error())
} else {
_, _ = fmt.Fprintf(builder, ", CRL info: issuer=%s, number=%s, next update=%s, revoked certificates=%d",
revlist.Issuer, revlist.Number, revlist.NextUpdate, len(revlist.RevokedCertificates))
_, _ = builder.WriteString(", CRL data:\n")
_ = pem.Encode(builder, &pem.Block{
Type: "CERTIFICATE REVOCATION LIST",
Bytes: r.CRLData,
})
}
}
return builder.String()
}
type ErrorResponse struct {
Message string `msgpack:"message"`
}
func BuildCommandAnnounce(code CommandCode) *CommandAnnounce {
return &CommandAnnounce{Code: code, Created: time.Now().UTC()}
}
func BuildResponseAnnounce(code ResponseCode) *ResponseAnnounce {
return &ResponseAnnounce{Code: code, Created: time.Now().UTC()}
}

View file

@ -26,6 +26,36 @@ func ___encode(i interface{}) ([]byte, error) {
// encodeAsArray
func ___encodeAsArray(i interface{}) ([]byte, error) {
switch v := i.(type) {
case HealthCommand:
encoder := enc.NewEncoder()
size, err := ___calcArraySizeHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeArrayHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthCommand", size, offset)
}
return b, err
case *HealthCommand:
encoder := enc.NewEncoder()
size, err := ___calcArraySizeHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeArrayHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthCommand", size, offset)
}
return b, err
case HealthInfo:
encoder := enc.NewEncoder()
size, err := ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
@ -86,6 +116,36 @@ func ___encodeAsArray(i interface{}) ([]byte, error) {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
}
return b, err
case FetchCRLResponse:
encoder := enc.NewEncoder()
size, err := ___calcArraySizeFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeArrayFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "FetchCRLResponse", size, offset)
}
return b, err
case *FetchCRLResponse:
encoder := enc.NewEncoder()
size, err := ___calcArraySizeFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeArrayFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "FetchCRLResponse", size, offset)
}
return b, err
case ErrorResponse:
encoder := enc.NewEncoder()
size, err := ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
@ -123,6 +183,36 @@ func ___encodeAsArray(i interface{}) ([]byte, error) {
// encodeAsMap
func ___encodeAsMap(i interface{}) ([]byte, error) {
switch v := i.(type) {
case HealthCommand:
encoder := enc.NewEncoder()
size, err := ___calcMapSizeHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthCommand", size, offset)
}
return b, err
case *HealthCommand:
encoder := enc.NewEncoder()
size, err := ___calcMapSizeHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthCommand", size, offset)
}
return b, err
case HealthInfo:
encoder := enc.NewEncoder()
size, err := ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
@ -183,6 +273,36 @@ func ___encodeAsMap(i interface{}) ([]byte, error) {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
}
return b, err
case FetchCRLResponse:
encoder := enc.NewEncoder()
size, err := ___calcMapSizeFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeMapFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "FetchCRLResponse", size, offset)
}
return b, err
case *FetchCRLResponse:
encoder := enc.NewEncoder()
size, err := ___calcMapSizeFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
if err != nil {
return nil, err
}
encoder.MakeBytes(size)
b, offset, err := ___encodeMapFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
if err != nil {
return nil, err
}
if size != offset {
return nil, fmt.Errorf("%s size / offset different %d : %d", "FetchCRLResponse", size, offset)
}
return b, err
case ErrorResponse:
encoder := enc.NewEncoder()
size, err := ___calcMapSizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
@ -229,6 +349,20 @@ func ___decode(data []byte, i interface{}) (bool, error) {
// decodeAsArray
func ___decodeAsArray(data []byte, i interface{}) (bool, error) {
switch v := i.(type) {
case *HealthCommand:
decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case **HealthCommand:
decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case *HealthInfo:
decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
@ -257,6 +391,20 @@ func ___decodeAsArray(data []byte, i interface{}) (bool, error) {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case *FetchCRLResponse:
decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case **FetchCRLResponse:
decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case *ErrorResponse:
decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
@ -278,6 +426,20 @@ func ___decodeAsArray(data []byte, i interface{}) (bool, error) {
// decodeAsMap
func ___decodeAsMap(data []byte, i interface{}) (bool, error) {
switch v := i.(type) {
case *HealthCommand:
decoder := dec.NewDecoder(data)
offset, err := ___decodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case **HealthCommand:
decoder := dec.NewDecoder(data)
offset, err := ___decodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case *HealthInfo:
decoder := dec.NewDecoder(data)
offset, err := ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
@ -306,6 +468,20 @@ func ___decodeAsMap(data []byte, i interface{}) (bool, error) {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case *FetchCRLResponse:
decoder := dec.NewDecoder(data)
offset, err := ___decodeMapFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case **FetchCRLResponse:
decoder := dec.NewDecoder(data)
offset, err := ___decodeMapFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, decoder, 0)
if err == nil && offset != decoder.Len() {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
}
return true, err
case *ErrorResponse:
decoder := dec.NewDecoder(data)
offset, err := ___decodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
@ -324,6 +500,81 @@ func ___decodeAsMap(data []byte, i interface{}) (bool, error) {
return false, nil
}
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthCommand
func ___calcArraySizeHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthCommand, encoder *enc.Encoder) (int, error) {
size := 0
size += encoder.CalcStructHeaderFix(0)
return size, nil
}
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthCommand
func ___calcMapSizeHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthCommand, encoder *enc.Encoder) (int, error) {
size := 0
size += encoder.CalcStructHeaderFix(0)
return size, nil
}
// encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthCommand
func ___encodeArrayHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthCommand, encoder *enc.Encoder, offset int) ([]byte, int, error) {
var err error
offset = encoder.WriteStructHeaderFixAsArray(0, offset)
return encoder.EncodedBytes(), offset, err
}
// encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthCommand
func ___encodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthCommand, encoder *enc.Encoder, offset int) ([]byte, int, error) {
var err error
offset = encoder.WriteStructHeaderFixAsMap(0, offset)
return encoder.EncodedBytes(), offset, err
}
// decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthCommand
func ___decodeArrayHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthCommand, decoder *dec.Decoder, offset int) (int, error) {
offset, err := decoder.CheckStructHeader(0, offset)
if err != nil {
return 0, err
}
return offset, err
}
// decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthCommand
func ___decodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthCommand, decoder *dec.Decoder, offset int) (int, error) {
keys := [][]byte{}
offset, err := decoder.CheckStructHeader(0, offset)
if err != nil {
return 0, err
}
count := 0
for count < 0 {
var dataKey []byte
dataKey, offset, err = decoder.AsStringBytes(offset)
if err != nil {
return 0, err
}
fieldIndex := -1
for i, key := range keys {
if len(dataKey) != len(key) {
continue
}
fieldIndex = i
for dataKeyIndex := range dataKey {
if dataKey[dataKeyIndex] != key[dataKeyIndex] {
fieldIndex = -1
break
}
}
if fieldIndex >= 0 {
break
}
}
switch fieldIndex {
default:
return 0, fmt.Errorf("unknown key[%s] found", string(dataKey))
}
}
return offset, err
}
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthInfo
func ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthInfo, encoder *enc.Encoder) (int, error) {
size := 0
@ -562,11 +813,16 @@ func ___calcArraySizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81
}
size += s
for _, vv := range v.Info {
size_vv, err := ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder)
if err != nil {
return 0, err
if vv != nil {
vvp := *vv
size_vvp, err := ___calcArraySizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vvp, encoder)
if err != nil {
return 0, err
}
size += size_vvp
} else {
size += encoder.CalcNil()
}
size += size_vv
}
} else {
size += encoder.CalcNil()
@ -590,11 +846,16 @@ func ___calcMapSizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a8137
}
size += s
for _, vv := range v.Info {
size_vv, err := ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder)
if err != nil {
return 0, err
if vv != nil {
vvp := *vv
size_vvp, err := ___calcMapSizeHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vvp, encoder)
if err != nil {
return 0, err
}
size += size_vvp
} else {
size += encoder.CalcNil()
}
size += size_vv
}
} else {
size += encoder.CalcNil()
@ -611,9 +872,14 @@ func ___encodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a8137
if v.Info != nil {
offset = encoder.WriteSliceLength(len(v.Info), offset, false)
for _, vv := range v.Info {
_, offset, err = ___encodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder, offset)
if err != nil {
return nil, 0, err
if vv != nil {
vvp := *vv
_, offset, err = ___encodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vvp, encoder, offset)
if err != nil {
return nil, 0, err
}
} else {
offset = encoder.WriteNil(offset)
}
}
} else {
@ -628,15 +894,20 @@ func ___encodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f
offset = encoder.WriteStructHeaderFixAsMap(3, offset)
offset = encoder.WriteStringFix("version", 7, offset)
offset = encoder.WriteString(v.Version, offset)
offset = encoder.WriteStringFix("Healthy", 7, offset)
offset = encoder.WriteStringFix("healthy", 7, offset)
offset = encoder.WriteBool(v.Healthy, offset)
offset = encoder.WriteStringFix("Info", 4, offset)
if v.Info != nil {
offset = encoder.WriteSliceLength(len(v.Info), offset, false)
for _, vv := range v.Info {
_, offset, err = ___encodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vv, encoder, offset)
if err != nil {
return nil, 0, err
if vv != nil {
vvp := *vv
_, offset, err = ___encodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(vvp, encoder, offset)
if err != nil {
return nil, 0, err
}
} else {
offset = encoder.WriteNil(offset)
}
}
} else {
@ -668,18 +939,24 @@ func ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a8137
v.Healthy = vv
}
if !decoder.IsCodeNil(offset) {
var vv []HealthInfo
var vv []*HealthInfo
var vvl int
vvl, offset, err = decoder.SliceLength(offset)
if err != nil {
return 0, err
}
vv = make([]HealthInfo, vvl)
vv = make([]*HealthInfo, vvl)
for vvi := range vv {
var vvv HealthInfo
offset, err = ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(&vvv, decoder, offset)
if err != nil {
return 0, err
var vvv *HealthInfo
if !decoder.IsCodeNil(offset) {
var vvvp HealthInfo
offset, err = ___decodeArrayHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(&vvvp, decoder, offset)
if err != nil {
return 0, err
}
vvv = &vvvp
} else {
offset++
}
vv[vvi] = vvv
}
@ -694,7 +971,7 @@ func ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a8137
func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthResponse, decoder *dec.Decoder, offset int) (int, error) {
keys := [][]byte{
{uint8(0x76), uint8(0x65), uint8(0x72), uint8(0x73), uint8(0x69), uint8(0x6f), uint8(0x6e)}, // version
{uint8(0x48), uint8(0x65), uint8(0x61), uint8(0x6c), uint8(0x74), uint8(0x68), uint8(0x79)}, // Healthy
{uint8(0x68), uint8(0x65), uint8(0x61), uint8(0x6c), uint8(0x74), uint8(0x68), uint8(0x79)}, // healthy
{uint8(0x49), uint8(0x6e), uint8(0x66), uint8(0x6f)}, // Info
}
offset, err := decoder.CheckStructHeader(3, offset)
@ -747,22 +1024,239 @@ func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f
count++
case 2:
if !decoder.IsCodeNil(offset) {
var vv []HealthInfo
var vv []*HealthInfo
var vvl int
vvl, offset, err = decoder.SliceLength(offset)
if err != nil {
return 0, err
}
vv = make([]HealthInfo, vvl)
vv = make([]*HealthInfo, vvl)
for vvi := range vv {
var vvv HealthInfo
offset, err = ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(&vvv, decoder, offset)
var vvv *HealthInfo
if !decoder.IsCodeNil(offset) {
var vvvp HealthInfo
offset, err = ___decodeMapHealthInfo_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(&vvvp, decoder, offset)
if err != nil {
return 0, err
}
vvv = &vvvp
} else {
offset++
}
vv[vvi] = vvv
}
v.Info = vv
} else {
offset++
}
count++
default:
return 0, fmt.Errorf("unknown key[%s] found", string(dataKey))
}
}
return offset, err
}
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.FetchCRLResponse
func ___calcArraySizeFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v FetchCRLResponse, encoder *enc.Encoder) (int, error) {
size := 0
size += encoder.CalcStructHeaderFix(3)
size += encoder.CalcString(v.IssuerID)
size += encoder.CalcBool(v.IsDelta)
if v.CRLData != nil {
s, err := encoder.CalcSliceLength(len(v.CRLData), true)
if err != nil {
return 0, err
}
size += s
for _, vv := range v.CRLData {
size += encoder.CalcByte(vv)
}
} else {
size += encoder.CalcNil()
}
return size, nil
}
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.FetchCRLResponse
func ___calcMapSizeFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v FetchCRLResponse, encoder *enc.Encoder) (int, error) {
size := 0
size += encoder.CalcStructHeaderFix(3)
size += encoder.CalcStringFix(9)
size += encoder.CalcString(v.IssuerID)
size += encoder.CalcStringFix(8)
size += encoder.CalcBool(v.IsDelta)
size += encoder.CalcStringFix(8)
if v.CRLData != nil {
s, err := encoder.CalcSliceLength(len(v.CRLData), true)
if err != nil {
return 0, err
}
size += s
for _, vv := range v.CRLData {
size += encoder.CalcByte(vv)
}
} else {
size += encoder.CalcNil()
}
return size, nil
}
// encode from git.cacert.org/cacert-gosigner/pkg/messages.FetchCRLResponse
func ___encodeArrayFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v FetchCRLResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) {
var err error
offset = encoder.WriteStructHeaderFixAsArray(3, offset)
offset = encoder.WriteString(v.IssuerID, offset)
offset = encoder.WriteBool(v.IsDelta, offset)
if v.CRLData != nil {
offset = encoder.WriteSliceLength(len(v.CRLData), offset, true)
for _, vv := range v.CRLData {
offset = encoder.WriteByte(vv, offset)
}
} else {
offset = encoder.WriteNil(offset)
}
return encoder.EncodedBytes(), offset, err
}
// encode from git.cacert.org/cacert-gosigner/pkg/messages.FetchCRLResponse
func ___encodeMapFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v FetchCRLResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) {
var err error
offset = encoder.WriteStructHeaderFixAsMap(3, offset)
offset = encoder.WriteStringFix("issuer_id", 9, offset)
offset = encoder.WriteString(v.IssuerID, offset)
offset = encoder.WriteStringFix("is_delta", 8, offset)
offset = encoder.WriteBool(v.IsDelta, offset)
offset = encoder.WriteStringFix("crl_data", 8, offset)
if v.CRLData != nil {
offset = encoder.WriteSliceLength(len(v.CRLData), offset, true)
for _, vv := range v.CRLData {
offset = encoder.WriteByte(vv, offset)
}
} else {
offset = encoder.WriteNil(offset)
}
return encoder.EncodedBytes(), offset, err
}
// decode to git.cacert.org/cacert-gosigner/pkg/messages.FetchCRLResponse
func ___decodeArrayFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *FetchCRLResponse, decoder *dec.Decoder, offset int) (int, error) {
offset, err := decoder.CheckStructHeader(3, offset)
if err != nil {
return 0, err
}
{
var vv string
vv, offset, err = decoder.AsString(offset)
if err != nil {
return 0, err
}
v.IssuerID = vv
}
{
var vv bool
vv, offset, err = decoder.AsBool(offset)
if err != nil {
return 0, err
}
v.IsDelta = vv
}
if !decoder.IsCodeNil(offset) {
var vv []byte
var vvl int
vvl, offset, err = decoder.SliceLength(offset)
if err != nil {
return 0, err
}
vv = make([]byte, vvl)
for vvi := range vv {
var vvv byte
vvv, offset, err = decoder.AsByte(offset)
if err != nil {
return 0, err
}
vv[vvi] = vvv
}
v.CRLData = vv
} else {
offset++
}
return offset, err
}
// decode to git.cacert.org/cacert-gosigner/pkg/messages.FetchCRLResponse
func ___decodeMapFetchCRLResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *FetchCRLResponse, decoder *dec.Decoder, offset int) (int, error) {
keys := [][]byte{
{uint8(0x69), uint8(0x73), uint8(0x73), uint8(0x75), uint8(0x65), uint8(0x72), uint8(0x5f), uint8(0x69), uint8(0x64)}, // issuer_id
{uint8(0x69), uint8(0x73), uint8(0x5f), uint8(0x64), uint8(0x65), uint8(0x6c), uint8(0x74), uint8(0x61)}, // is_delta
{uint8(0x63), uint8(0x72), uint8(0x6c), uint8(0x5f), uint8(0x64), uint8(0x61), uint8(0x74), uint8(0x61)}, // crl_data
}
offset, err := decoder.CheckStructHeader(3, offset)
if err != nil {
return 0, err
}
count := 0
for count < 3 {
var dataKey []byte
dataKey, offset, err = decoder.AsStringBytes(offset)
if err != nil {
return 0, err
}
fieldIndex := -1
for i, key := range keys {
if len(dataKey) != len(key) {
continue
}
fieldIndex = i
for dataKeyIndex := range dataKey {
if dataKey[dataKeyIndex] != key[dataKeyIndex] {
fieldIndex = -1
break
}
}
if fieldIndex >= 0 {
break
}
}
switch fieldIndex {
case 0:
{
var vv string
vv, offset, err = decoder.AsString(offset)
if err != nil {
return 0, err
}
v.IssuerID = vv
}
count++
case 1:
{
var vv bool
vv, offset, err = decoder.AsBool(offset)
if err != nil {
return 0, err
}
v.IsDelta = vv
}
count++
case 2:
if !decoder.IsCodeNil(offset) {
var vv []byte
var vvl int
vvl, offset, err = decoder.SliceLength(offset)
if err != nil {
return 0, err
}
vv = make([]byte, vvl)
for vvi := range vv {
var vvv byte
vvv, offset, err = decoder.AsByte(offset)
if err != nil {
return 0, err
}
vv[vvi] = vvv
}
v.Info = vv
v.CRLData = vv
} else {
offset++
}

View file

@ -19,71 +19,116 @@ limitations under the License.
package protocol
import (
"errors"
"fmt"
"time"
"github.com/shamaton/msgpackgen/msgpack"
"github.com/sirupsen/logrus"
"git.cacert.org/cacert-gosigner/pkg/x509/revoking"
"git.cacert.org/cacert-gosigner/pkg/health"
"git.cacert.org/cacert-gosigner/pkg/messages"
)
// Handler is responsible for parsing incoming frames and calling commands
type Handler interface {
HandleFrame([]byte) ([]byte, error)
HandleCommandAnnounce([]byte) (*messages.CommandAnnounce, error)
HandleCommand(*messages.CommandAnnounce, []byte) ([]byte, []byte, error)
}
type MsgPackHandler struct {
logger *logrus.Logger
healthHandler *health.Handler
logger *logrus.Logger
healthHandler *health.Handler
fetchCRLHandler *revoking.FetchCRLHandler
}
func (m *MsgPackHandler) HandleFrame(frame []byte) ([]byte, error) {
var command messages.Command
func (m *MsgPackHandler) HandleCommandAnnounce(frame []byte) (*messages.CommandAnnounce, error) {
var ann messages.CommandAnnounce
err := msgpack.Unmarshal(frame, &command)
if err != nil {
m.logger.Errorf("unmarshal failed: %v", err)
errorResponse, innerErr := buildErrorResponse("do not understand")
if innerErr != nil {
return nil, innerErr
}
return errorResponse, nil
if err := msgpack.Unmarshal(frame, &ann); err != nil {
return nil, fmt.Errorf("could not unmarshal command announcement: %w", err)
}
m.logger.Infof("Received %s command sent at %s", command.Code, command.TimeStamp)
m.logger.Infof("received command announcement %+v", ann)
response, err := m.handleCommand(&command)
if err != nil {
m.logger.Errorf("command failed: %v", err)
errorResponse, innerErr := buildErrorResponse("command failed")
if innerErr != nil {
return nil, innerErr
}
return errorResponse, nil
}
responseData, err := msgpack.Marshal(response)
if err != nil {
return nil, fmt.Errorf("could not marshal response: %w", err)
}
return responseData, nil
return &ann, nil
}
func (m *MsgPackHandler) handleCommand(command *messages.Command) (*messages.Response, error) {
func (m *MsgPackHandler) HandleCommand(announce *messages.CommandAnnounce, frame []byte) ([]byte, []byte, error) {
var (
response *Response
clientError, err error
)
switch announce.Code {
case messages.CmdHealth:
// health has no payload, ignore the frame
response, err = m.handleCommand(&Command{Announce: announce, Command: nil})
if err != nil {
m.logger.WithError(err).Error("health handling failed")
clientError = errors.New("could not handle request")
}
case messages.CmdFetchCRL:
var command messages.FetchCRLCommand
err = msgpack.Unmarshal(frame, &command)
if err != nil {
m.logger.WithError(err).Error("unmarshal failed")
clientError = errors.New("could not unmarshal fetch crl command")
break
}
response, err = m.handleCommand(&Command{Announce: announce, Command: command})
if err != nil {
m.logger.WithError(err).Error("fetch CRL handling failed")
clientError = errors.New("could not handle request")
}
}
if clientError != nil {
response = buildErrorResponse(clientError.Error())
}
announceData, err := msgpack.Marshal(response.Announce)
if err != nil {
return nil, nil, fmt.Errorf("could not marshal response announcement: %w", err)
}
responseData, err := msgpack.Marshal(response.Response)
if err != nil {
return nil, nil, fmt.Errorf("could not marshal response: %w", err)
}
return announceData, responseData, nil
}
type Command struct {
Announce *messages.CommandAnnounce
Command interface{}
}
type Response struct {
Announce *messages.ResponseAnnounce
Response interface{}
}
func (r *Response) String() string {
return fmt.Sprintf("Response[Code=%s] created=%s data=%s", r.Announce.Code, r.Announce.Created, r.Response)
}
func (m *MsgPackHandler) handleCommand(command *Command) (*Response, error) {
var (
err error
payload interface{}
responseData interface{}
responseCode messages.ResponseCode
)
switch command.Code {
switch command.Announce.Code {
case messages.CmdHealth:
var res *health.Result
@ -98,36 +143,52 @@ func (m *MsgPackHandler) handleCommand(command *messages.Command) (*messages.Res
}
for _, info := range res.Info {
response.Info = append(response.Info, messages.HealthInfo{
response.Info = append(response.Info, &messages.HealthInfo{
Source: info.Source,
Healthy: info.Healthy,
MoreInfo: info.MoreInfo,
})
}
responseCode, payload = messages.RspHealth, response
responseCode, responseData = messages.RespHealth, response
case messages.CmdFetchCRL:
var res *revoking.Result
fetchCRLPayload, ok := command.Command.(messages.FetchCRLCommand)
if !ok {
return nil, fmt.Errorf("could not use payload as FetchCRLPayload")
}
res, err = m.fetchCRLHandler.FetchCRL(fetchCRLPayload.IssuerID)
if err != nil {
break
}
response := messages.FetchCRLResponse{
IsDelta: false,
CRLData: res.Data,
}
responseCode, responseData = messages.RespFetchCRL, response
default:
return nil, fmt.Errorf("unhandled command %s", command)
return nil, fmt.Errorf("unhandled command %v", command)
}
if err != nil {
return nil, fmt.Errorf("error from command handler: %w", err)
}
return &messages.Response{TimeStamp: time.Now().UTC(), Code: responseCode, Payload: payload}, nil
return &Response{
Announce: messages.BuildResponseAnnounce(responseCode),
Response: responseData,
}, nil
}
func buildErrorResponse(errMsg string) ([]byte, error) {
marshal, err := msgpack.Marshal(&messages.Response{
Code: messages.RspError,
TimeStamp: time.Now().UTC(),
Payload: messages.ErrorResponse{Message: errMsg},
})
if err != nil {
return nil, fmt.Errorf("could not marshal error response: %w", err)
func buildErrorResponse(errMsg string) *Response {
return &Response{
Announce: messages.BuildResponseAnnounce(messages.RespError),
Response: messages.ErrorResponse{Message: errMsg},
}
return marshal, nil
}
func New(logger *logrus.Logger, handlers ...RegisterHandler) (Handler, error) {
@ -151,3 +212,9 @@ func RegisterHealthHandler(healthHandler *health.Handler) func(*MsgPackHandler)
h.healthHandler = healthHandler
}
}
func RegisterFetchCRLHandler(fetchCRLHandler *revoking.FetchCRLHandler) func(handler *MsgPackHandler) {
return func(h *MsgPackHandler) {
h.fetchCRLHandler = fetchCRLHandler
}
}

View file

@ -19,6 +19,7 @@ limitations under the License.
package seriallink
import (
"bytes"
"fmt"
"time"
@ -29,8 +30,17 @@ import (
"git.cacert.org/cacert-gosigner/pkg/protocol"
)
type protocolState int8
const (
stAnnounce protocolState = iota
stCommand
)
type Handler struct {
protocolHandler protocol.Handler
protocolState protocolState
currentCommand *protocol.Command
config *serial.Config
port *serial.Port
}
@ -57,6 +67,8 @@ func (h *Handler) Close() error {
const cobsDelimiter = 0x00
var cobsConfig = cobs.Config{SpecialByte: cobsDelimiter, Delimiter: true, EndingSave: true}
func (h *Handler) Run() error {
const (
bufferSize = 1024 * 1024
@ -65,7 +77,7 @@ func (h *Handler) Run() error {
errors := make(chan error)
cobsConfig := cobs.Config{SpecialByte: cobsDelimiter, Delimiter: true, EndingSave: true}
h.protocolState = stAnnounce
go func() {
buf := make([]byte, bufferSize)
@ -84,28 +96,9 @@ func (h *Handler) Run() error {
continue
}
err = cobs.Verify(buf[:count], cobsConfig)
if err != nil {
errors <- err
frames := bytes.SplitAfter(buf[:count], []byte{cobsDelimiter})
return
}
// perform COBS decoding
decoded := cobs.Decode(buf[:count], cobsConfig)
msg, err := h.protocolHandler.HandleFrame(decoded)
if err != nil {
errors <- err
return
}
// perform COBS encoding
encoded := cobs.Encode(msg, cobsConfig)
_, err = h.port.Write(encoded)
if err != nil {
if err := h.handleFrames(frames); err != nil {
errors <- err
return
@ -121,6 +114,96 @@ func (h *Handler) Run() error {
return nil
}
func (h *Handler) handleFrames(frames [][]byte) error {
for _, frame := range frames {
if len(frame) == 0 {
return nil
}
if err := cobs.Verify(frame, cobsConfig); err != nil {
return fmt.Errorf("could not verify COBS frame: %w", err)
}
// perform COBS decoding
decoded := cobs.Decode(frame, cobsConfig)
if h.protocolState == stAnnounce {
if err := h.handleCommandAnnounce(decoded); err != nil {
return err
}
}
if h.protocolState == stCommand {
if err := h.handleCommandData(decoded); err != nil {
return err
}
}
if err := h.nextState(); err != nil {
return err
}
}
return nil
}
func (h *Handler) handleCommandData(decoded []byte) error {
respAnn, msg, err := h.protocolHandler.HandleCommand(h.currentCommand.Announce, decoded)
if err != nil {
return fmt.Errorf("command handler for %s failed: %w", h.currentCommand.Announce.Code, err)
}
if err := h.writeResponse(respAnn, msg, cobsConfig); err != nil {
return err
}
return nil
}
func (h *Handler) handleCommandAnnounce(decoded []byte) error {
announce, err := h.protocolHandler.HandleCommandAnnounce(decoded)
if err != nil {
return fmt.Errorf("command announce handling failed: %w", err)
}
h.currentCommand = &protocol.Command{Announce: announce}
return nil
}
func (h *Handler) writeResponse(ann, msg []byte, cobsConfig cobs.Config) error {
encoded := cobs.Encode(ann, cobsConfig)
if _, err := h.port.Write(encoded); err != nil {
return fmt.Errorf("could not write response announcement: %w", err)
}
encoded = cobs.Encode(msg, cobsConfig)
if _, err := h.port.Write(encoded); err != nil {
return fmt.Errorf("could not write response: %w", err)
}
return nil
}
func (h *Handler) nextState() error {
var next protocolState
switch h.protocolState {
case stAnnounce:
next = stCommand
case stCommand:
next = stAnnounce
default:
return fmt.Errorf("illegal protocol state %d", int(h.protocolState))
}
h.protocolState = next
return nil
}
func New(cfg *config.Serial, protocolHandler protocol.Handler) (*Handler, error) {
h := &Handler{protocolHandler: protocolHandler}
h.config = &serial.Config{Name: cfg.Device, Baud: cfg.Baud, ReadTimeout: cfg.Timeout}

View file

@ -92,9 +92,45 @@ func (ie *indexEntry) String() string {
// A reference for the file format can be found at
// https://pki-tutorial.readthedocs.io/en/latest/cadb.html.
type Repository struct {
indexFileName string
lock sync.Locker
entries []indexEntry
indexFileName string
crlNumberFileName string
lock sync.Locker
entries []indexEntry
}
func (r *Repository) NextCRLNumber() (*big.Int, error) {
r.lock.Lock()
defer r.lock.Unlock()
number := big.NewInt(0)
data, err := os.ReadFile(r.crlNumberFileName)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf(
"could not read next CRL number from file %s: %w",
r.crlNumberFileName,
err,
)
}
} else {
if _, ok := number.SetString(string(data), 16); !ok {
return nil, fmt.Errorf("could not parse %s as CRL serial number", data)
}
}
number.Add(number, big.NewInt(1))
err = os.WriteFile(r.crlNumberFileName, []byte(number.Text(16)), 0600) //nolint:gomnd
if err != nil {
return nil, fmt.Errorf(
"could not write next CRL serial number to file %s: %w",
r.crlNumberFileName,
err,
)
}
return number, nil
}
func (ie *indexEntry) markRevoked(revocationTime time.Time, reason revoking.CRLReason) {
@ -378,13 +414,21 @@ func (r *Repository) newIndexEntryFromLine(text string) (*indexEntry, error) {
}
func NewFileRepository(baseDirectory string) (*Repository, error) {
err := os.Chdir(baseDirectory)
_, err := os.ReadDir(baseDirectory)
if err != nil {
return nil, fmt.Errorf("could not change to base directory %s: %w", baseDirectory, err)
if !errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("could not change to base directory %s: %w", baseDirectory, err)
}
err = os.MkdirAll(baseDirectory, 0750) //nolint:gomnd
if err != nil {
return nil, fmt.Errorf("could not create base directory %s: %w", baseDirectory, err)
}
}
return &Repository{
indexFileName: path.Join(baseDirectory, "index.txt"),
lock: &sync.Mutex{},
indexFileName: path.Join(baseDirectory, "index.txt"),
crlNumberFileName: path.Join(baseDirectory, "crlnumber"),
lock: &sync.Mutex{},
}, nil
}

View file

@ -32,6 +32,8 @@ import (
var OidCRLReason = asn1.ObjectIdentifier{2, 5, 29, 21}
const defaultCRLValidity = 24 * time.Hour
type CRLReason int
// CRL reason codes as defined in RFC 5280 section 5.3.1
@ -138,6 +140,7 @@ func (r *X509Revoking) CreateCRL() (*CRLInformation, error) {
SignatureAlgorithm: r.crlAlgorithm,
RevokedCertificates: revoked,
Number: nextNumber,
NextUpdate: time.Now().UTC().Add(defaultCRLValidity),
}, r.crlIssuer, r.signer)
if err != nil {
return nil, fmt.Errorf("could not sign revocation list: %w", err)
@ -154,3 +157,29 @@ func NewX509Revoking(
) *X509Revoking {
return &X509Revoking{repository: repo, crlAlgorithm: crlAlgorithm, crlIssuer: issuer, signer: signer}
}
type Result struct {
Data []byte
}
type FetchCRLHandler struct {
repositories map[string]*X509Revoking
}
func NewFetchCRLHandler(repositories map[string]*X509Revoking) *FetchCRLHandler {
return &FetchCRLHandler{repositories: repositories}
}
func (h *FetchCRLHandler) FetchCRL(issuerID string) (*Result, error) {
repo, ok := h.repositories[issuerID]
if !ok {
return nil, fmt.Errorf("unknown issuer ID %s", issuerID)
}
currentCRL, err := repo.CreateCRL()
if err != nil {
return nil, fmt.Errorf("could not create CRL for issuer ID %s: %w", issuerID, err)
}
return &Result{Data: currentCRL.CRL}, nil
}