Protocol improvements

- add a client generated command ID for tracing commands and responses
- define protocol delimiter in protocol.CobsDelimiter
- apply code simplifications suggested by golangci-lint
- add Makefile
- add compile time build information for signer binary
- make sure that dependencies for msgpackgen survive go mod tidy
- extract MsgPackHandler into its own file
- add CRL number to fetch CRL response
- remove port.Flush() to avoid removing written data before it reaches the
  client
main
Jan Dittberner 2 years ago
parent 8e443bd8b4
commit f0d456dd13

@ -0,0 +1,26 @@
GOFILES := $(shell find -type f -name '*.go')
BUILD_TIME := $(shell date --rfc-3339=seconds)
COMMIT := $(shell git show-ref --head --abbrev=8 HEAD|cut -d ' ' -f 1)
VERSION := $(shell git describe --always --dirty)
all: pkg/messages/resolver.msgpackgen.go lint test clientsim signer
pkg/messages/resolver.msgpackgen.go: pkg/messages/messages.go
go generate $<
lint:
golangci-lint run
test:
go test -race ./...
clientsim: $(GOFILES)
go build -race ./cmd/clientsim
signer: $(GOFILES)
go build -race -ldflags="-X 'main.date=$(BUILD_TIME)' -X 'main.commit=$(COMMIT)' -X 'main.version=$(VERSION)'" ./cmd/signer
clean:
rm -f signer clientsim pkg/messages/resolver.msgpackgen.go
.PHONY: test lint all clean

@ -37,7 +37,7 @@ import (
"git.cacert.org/cacert-gosigner/pkg/messages" "git.cacert.org/cacert-gosigner/pkg/messages"
) )
var cobsConfig = cobs.Config{SpecialByte: 0x00, Delimiter: true, EndingSave: true} var cobsConfig = cobs.Config{SpecialByte: protocol.CobsDelimiter, Delimiter: true, EndingSave: true}
type protocolState int8 type protocolState int8
@ -82,17 +82,16 @@ func (g *TestCommandGenerator) CmdAnnouncement() ([]byte, error) {
g.lock.Lock() g.lock.Lock()
defer g.lock.Unlock() defer g.lock.Unlock()
select { g.currentCommand = <-g.commands
case g.currentCommand = <-g.commands:
announceData, err := msgpack.Marshal(g.currentCommand.Announce)
if err != nil {
return nil, fmt.Errorf("could not marshal command annoucement: %w", err)
}
g.logger.WithField("announcement", &g.currentCommand.Announce).Info("write command announcement") announceData, err := msgpack.Marshal(g.currentCommand.Announce)
if err != nil {
return announceData, nil return nil, fmt.Errorf("could not marshal command annoucement: %w", err)
} }
g.logger.WithField("announcement", &g.currentCommand.Announce).Info("write command announcement")
return announceData, nil
} }
func (g *TestCommandGenerator) CmdData() ([]byte, error) { func (g *TestCommandGenerator) CmdData() ([]byte, error) {
@ -138,13 +137,15 @@ func (g *TestCommandGenerator) HandleResponse(frame []byte) error {
return fmt.Errorf("unmarshal failed: %w", err) return fmt.Errorf("unmarshal failed: %w", err)
} }
g.currentResponse.Response = response g.currentResponse.Response = &response
case messages.RespFetchCRL: case messages.RespFetchCRL:
var response messages.FetchCRLResponse var response messages.FetchCRLResponse
if err := msgpack.Unmarshal(frame, &response); err != nil { if err := msgpack.Unmarshal(frame, &response); err != nil {
return fmt.Errorf("unmarshal failed: %w", err) return fmt.Errorf("unmarshal failed: %w", err)
} }
g.currentResponse.Response = &response
} }
g.logger.WithField( g.logger.WithField(
@ -159,14 +160,27 @@ func (g *TestCommandGenerator) HandleResponse(frame []byte) error {
} }
func (g *TestCommandGenerator) GenerateCommands(ctx context.Context) error { func (g *TestCommandGenerator) GenerateCommands(ctx context.Context) error {
const healthInterval = 10 * time.Second const (
healthInterval = 5 * time.Second
startPause = 3 * time.Second
)
var (
announce *messages.CommandAnnounce
err error
)
g.logger.Info("start generating commands") g.logger.Info("start generating commands")
time.Sleep(healthInterval) time.Sleep(startPause)
announce, err = messages.BuildCommandAnnounce(messages.CmdFetchCRL)
if err != nil {
return fmt.Errorf("build command announce failed: %w", err)
}
g.commands <- &protocol.Command{ g.commands <- &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdFetchCRL), Announce: announce,
Command: &messages.FetchCRLCommand{IssuerID: "sub-ecc_person_2022"}, Command: &messages.FetchCRLCommand{IssuerID: "sub-ecc_person_2022"},
} }
@ -181,8 +195,13 @@ func (g *TestCommandGenerator) GenerateCommands(ctx context.Context) error {
return nil return nil
case <-timer.C: case <-timer.C:
announce, err = messages.BuildCommandAnnounce(messages.CmdHealth)
if err != nil {
return fmt.Errorf("build command announce failed: %w", err)
}
g.commands <- &protocol.Command{ g.commands <- &protocol.Command{
Announce: messages.BuildCommandAnnounce(messages.CmdHealth), Announce: announce,
Command: &messages.HealthCommand{}, Command: &messages.HealthCommand{},
} }
} }
@ -203,7 +222,9 @@ func (c *clientSimulator) readFrames() error {
const readInterval = 50 * time.Millisecond const readInterval = 50 * time.Millisecond
var frame []byte var frame []byte
buffer := &bytes.Buffer{} buffer := &bytes.Buffer{}
delimiter := []byte{cobsConfig.SpecialByte} delimiter := []byte{cobsConfig.SpecialByte}
for { for {
@ -231,6 +252,8 @@ func (c *clientSimulator) readFrames() error {
rest := buffer.Bytes() rest := buffer.Bytes()
if !bytes.Contains(rest, delimiter) { if !bytes.Contains(rest, delimiter) {
c.logger.Tracef("read data does not contain the delimiter %x", delimiter)
continue continue
} }
@ -254,6 +277,8 @@ func (c *clientSimulator) readFrames() error {
c.logger.Tracef("frame decoded to length %d", len(decoded)) c.logger.Tracef("frame decoded to length %d", len(decoded))
c.framesIn <- decoded c.framesIn <- decoded
c.logger.Tracef("%d bytes remaining", len(rest))
} }
buffer.Truncate(0) buffer.Truncate(0)
@ -266,9 +291,6 @@ func (c *clientSimulator) readFrames() error {
func (c *clientSimulator) writeFrame(frame []byte) error { func (c *clientSimulator) writeFrame(frame []byte) error {
encoded := cobs.Encode(frame, cobsConfig) encoded := cobs.Encode(frame, cobsConfig)
c.lock.Lock()
defer c.lock.Unlock()
if _, err := io.Copy(os.Stdout, bytes.NewBuffer(encoded)); err != nil { if _, err := io.Copy(os.Stdout, bytes.NewBuffer(encoded)); err != nil {
return fmt.Errorf("could not write data: %w", err) return fmt.Errorf("could not write data: %w", err)
} }
@ -281,11 +303,15 @@ func (c *clientSimulator) readFromStdin() ([]byte, error) {
buf := make([]byte, bufferSize) buf := make([]byte, bufferSize)
c.logger.Trace("waiting for input")
count, err := os.Stdin.Read(buf) count, err := os.Stdin.Read(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("reading input failed: %w", err) return nil, fmt.Errorf("reading input failed: %w", err)
} }
c.logger.Tracef("read %d bytes from stdin", count)
return buf[:count], nil return buf[:count], nil
} }
@ -308,25 +334,6 @@ func (c *clientSimulator) writeCmdAnnouncement() error {
return nil return nil
} }
func (c *clientSimulator) writeCommandAnnouncement() error {
frame, err := c.commandGenerator.CmdAnnouncement()
if err != nil {
return fmt.Errorf("could not get command announcement: %w", err)
}
c.logger.Trace("writing command announcement")
if err := c.writeFrame(frame); err != nil {
return err
}
if err := c.nextState(); err != nil {
return err
}
return nil
}
func (c *clientSimulator) writeCommand() error { func (c *clientSimulator) writeCommand() error {
frame, err := c.commandGenerator.CmdData() frame, err := c.commandGenerator.CmdData()
if err != nil { if err != nil {
@ -349,19 +356,18 @@ func (c *clientSimulator) writeCommand() error {
func (c *clientSimulator) handleResponseAnnounce() error { func (c *clientSimulator) handleResponseAnnounce() error {
c.logger.Trace("waiting for response announce") c.logger.Trace("waiting for response announce")
select { frame := <-c.framesIn
case frame := <-c.framesIn:
if frame == nil {
return nil
}
if err := c.commandGenerator.HandleResponseAnnounce(frame); err != nil { if frame == nil {
return fmt.Errorf("response announce handling failed: %w", err) return nil
} }
if err := c.nextState(); err != nil { if err := c.commandGenerator.HandleResponseAnnounce(frame); err != nil {
return err return fmt.Errorf("response announce handling failed: %w", err)
} }
if err := c.nextState(); err != nil {
return err
} }
return nil return nil
@ -370,19 +376,18 @@ func (c *clientSimulator) handleResponseAnnounce() error {
func (c *clientSimulator) handleResponseData() error { func (c *clientSimulator) handleResponseData() error {
c.logger.Trace("waiting for response data") c.logger.Trace("waiting for response data")
select { frame := <-c.framesIn
case frame := <-c.framesIn:
if frame == nil {
return nil
}
if err := c.commandGenerator.HandleResponse(frame); err != nil { if frame == nil {
return fmt.Errorf("response handler failed: %w", err) return nil
} }
if err := c.nextState(); err != nil { if err := c.commandGenerator.HandleResponse(frame); err != nil {
return err return fmt.Errorf("response handler failed: %w", err)
} }
if err := c.nextState(); err != nil {
return err
} }
return nil return nil
@ -412,6 +417,7 @@ func (c *clientSimulator) Run(ctx context.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("error from handler loop: %w", err) return fmt.Errorf("error from handler loop: %w", err)
} }
return nil return nil
default: default:
if err := c.handleProtocolState(); err != nil { if err := c.handleProtocolState(); err != nil {
@ -424,6 +430,9 @@ func (c *clientSimulator) Run(ctx context.Context) error {
func (c *clientSimulator) handleProtocolState() error { func (c *clientSimulator) handleProtocolState() error {
c.logger.Tracef("handling protocol state %s", c.protocolState) c.logger.Tracef("handling protocol state %s", c.protocolState)
c.lock.Lock()
defer c.lock.Unlock()
switch c.protocolState { switch c.protocolState {
case cmdAnnounce: case cmdAnnounce:
if err := c.writeCmdAnnouncement(); err != nil { if err := c.writeCmdAnnouncement(); err != nil {
@ -462,17 +471,17 @@ func (c *clientSimulator) nextState() error {
func main() { func main() {
logger := logrus.New() logger := logrus.New()
logger.SetOutput(os.Stderr) logger.SetOutput(os.Stderr)
logger.SetLevel(logrus.TraceLevel) logger.SetLevel(logrus.DebugLevel)
messages.RegisterGeneratedResolver() messages.RegisterGeneratedResolver()
sim := &clientSimulator{ sim := &clientSimulator{
commandGenerator: &TestCommandGenerator{ commandGenerator: &TestCommandGenerator{
logger: logger, logger: logger,
commands: make(chan *protocol.Command, 0), commands: make(chan *protocol.Command),
}, },
logger: logger, logger: logger,
framesIn: make(chan []byte, 0), framesIn: make(chan []byte),
} }
err := sim.Run(context.Background()) err := sim.Run(context.Background())

@ -35,9 +35,9 @@ import (
) )
var ( var (
commit string commit = "dev"
date string date = "unknown"
version string version = "unknown"
) )
const ( const (

@ -4,6 +4,8 @@ go 1.17
require ( require (
github.com/ThalesIgnite/crypto11 v1.2.5 github.com/ThalesIgnite/crypto11 v1.2.5
github.com/dave/jennifer v1.4.1
github.com/google/uuid v1.3.0
github.com/justincpresley/go-cobs v1.2.0 github.com/justincpresley/go-cobs v1.2.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
@ -14,7 +16,6 @@ require (
) )
require ( require (
github.com/dave/jennifer v1.4.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect

@ -5,6 +5,8 @@ github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpT
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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 h1:dyWszWzXObEv8sxVMJTAIo9XT7HEM10vkAOZq2eVEsQ=
github.com/justincpresley/go-cobs v1.2.0/go.mod h1:L0d+EbGirv6IzsXNzwULduI2/z3ijkkAmsAuPMpLfqA= 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.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=

@ -24,8 +24,14 @@ import (
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"math/big"
"strings" "strings"
"time" "time"
// required for msgpackgen
_ "github.com/dave/jennifer"
"github.com/google/uuid"
) )
type CommandCode int8 type CommandCode int8
@ -72,33 +78,48 @@ func (c ResponseCode) String() string {
type CommandAnnounce struct { type CommandAnnounce struct {
Code CommandCode `msgpack:"code"` Code CommandCode `msgpack:"code"`
ID string `msgpack:"id"`
Created time.Time `msgpack:"created"` Created time.Time `msgpack:"created"`
} }
func (r *CommandAnnounce) String() string { func (r *CommandAnnounce) String() string {
return fmt.Sprintf("CommandAnnounce[code=%s, created=%s]", r.Code, r.Created) return fmt.Sprintf("code=%s, id=%s, created=%s", r.Code, r.ID, r.Created.Format(time.RFC3339))
} }
type ResponseAnnounce struct { type ResponseAnnounce struct {
Code ResponseCode `msgpack:"code"` Code ResponseCode `msgpack:"code"`
Created time.Time `msgpack:"created"` Created time.Time `msgpack:"created"`
ID string `msgpack:"id"`
} }
func (r *ResponseAnnounce) String() string { func (r *ResponseAnnounce) String() string {
return fmt.Sprintf("ResponseAnnounce[code=%s, created=%s]", r.Code, r.Created) return fmt.Sprintf("code=%s, id=%s, created=%s", r.Code, r.ID, r.Created.Format(time.RFC3339))
} }
type FetchCRLCommand struct { type FetchCRLCommand struct {
IssuerID string `msgpack:"issuer_id"` IssuerID string `msgpack:"issuer_id"`
LastKnownHash struct { LastKnownID *big.Int `msgpack:"last_known_id"`
Algorithm string `msgpack:"algorithm"` }
Value string `msgpack:"value"`
} `msgpack:"last_known_hash"` // optional last known hash in format func (f *FetchCRLCommand) String() string {
builder := &strings.Builder{}
_, _ = fmt.Fprintf(builder, "issuerId='%s'", f.IssuerID)
if f.LastKnownID != nil {
_, _ = fmt.Fprintf(builder, ", lastKnownId=%s", f.LastKnownID.Text(16))
}
return builder.String()
} }
type HealthCommand struct { type HealthCommand struct {
} }
func (h *HealthCommand) String() string {
return ""
}
type HealthInfo struct { type HealthInfo struct {
Source string Source string
Healthy bool Healthy bool
@ -138,9 +159,10 @@ func (h *HealthResponse) String() string {
} }
type FetchCRLResponse struct { type FetchCRLResponse struct {
IssuerID string `msgpack:"issuer_id"` IssuerID string `msgpack:"issuer_id"`
IsDelta bool `msgpack:"is_delta"` IsDelta bool `msgpack:"is_delta"`
CRLData []byte `msgpack:"crl_data"` CRLData []byte `msgpack:"crl_data"`
CRLNumber *big.Int
} }
func (r *FetchCRLResponse) String() string { func (r *FetchCRLResponse) String() string {
@ -151,12 +173,18 @@ func (r *FetchCRLResponse) String() string {
if r.IsDelta { if r.IsDelta {
_, _ = fmt.Fprint(builder, ", delta CRL data not shown") _, _ = fmt.Fprint(builder, ", delta CRL data not shown")
} else { } else {
revlist, err := x509.ParseRevocationList(r.CRLData) revocationList, err := x509.ParseRevocationList(r.CRLData)
if err != nil { if err != nil {
_, _ = fmt.Fprintf(builder, ", could not parse CRL: %s", err.Error()) _, _ = fmt.Fprintf(builder, ", could not parse CRL: %s", err.Error())
} else { } else {
_, _ = fmt.Fprintf(builder, ", CRL info: issuer=%s, number=%s, next update=%s, revoked certificates=%d", _, _ = fmt.Fprintf(
revlist.Issuer, revlist.Number, revlist.NextUpdate, len(revlist.RevokedCertificates)) builder,
", CRL info: issuer=%s, number=%s, next update=%s, revoked certificates=%d",
revocationList.Issuer,
revocationList.Number,
revocationList.NextUpdate,
len(revocationList.RevokedCertificates),
)
_, _ = builder.WriteString(", CRL data:\n") _, _ = builder.WriteString(", CRL data:\n")
_ = pem.Encode(builder, &pem.Block{ _ = pem.Encode(builder, &pem.Block{
Type: "CERTIFICATE REVOCATION LIST", Type: "CERTIFICATE REVOCATION LIST",
@ -172,10 +200,19 @@ type ErrorResponse struct {
Message string `msgpack:"message"` Message string `msgpack:"message"`
} }
func BuildCommandAnnounce(code CommandCode) *CommandAnnounce { func (e *ErrorResponse) String() string {
return &CommandAnnounce{Code: code, Created: time.Now().UTC()} return fmt.Sprintf("message=%s", e.Message)
}
func BuildCommandAnnounce(code CommandCode) (*CommandAnnounce, error) {
commandID, err := uuid.NewUUID()
if err != nil {
return nil, fmt.Errorf("could not build command id: %w", err)
}
return &CommandAnnounce{Code: code, ID: commandID.String(), Created: time.Now().UTC()}, nil
} }
func BuildResponseAnnounce(code ResponseCode) *ResponseAnnounce { func BuildResponseAnnounce(code ResponseCode, commandID string) *ResponseAnnounce {
return &ResponseAnnounce{Code: code, Created: time.Now().UTC()} return &ResponseAnnounce{Code: code, ID: commandID, Created: time.Now().UTC()}
} }

@ -116,36 +116,6 @@ func ___encodeAsArray(i interface{}) ([]byte, error) {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset) return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
} }
return b, err 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: case ErrorResponse:
encoder := enc.NewEncoder() encoder := enc.NewEncoder()
size, err := ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) size, err := ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
@ -273,36 +243,6 @@ func ___encodeAsMap(i interface{}) ([]byte, error) {
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset) return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
} }
return b, err 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: case ErrorResponse:
encoder := enc.NewEncoder() encoder := enc.NewEncoder()
size, err := ___calcMapSizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) size, err := ___calcMapSizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
@ -391,20 +331,6 @@ func ___decodeAsArray(data []byte, i interface{}) (bool, error) {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
} }
return true, err 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: case *ErrorResponse:
decoder := dec.NewDecoder(data) decoder := dec.NewDecoder(data)
offset, err := ___decodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) offset, err := ___decodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
@ -468,20 +394,6 @@ func ___decodeAsMap(data []byte, i interface{}) (bool, error) {
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
} }
return true, err 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: case *ErrorResponse:
decoder := dec.NewDecoder(data) decoder := dec.NewDecoder(data)
offset, err := ___decodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) offset, err := ___decodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0)
@ -1057,217 +969,6 @@ func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f
return offset, err 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.CRLData = 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.ErrorResponse // calculate size from git.cacert.org/cacert-gosigner/pkg/messages.ErrorResponse
func ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder) (int, error) { func ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder) (int, error) {
size := 0 size := 0

@ -0,0 +1,282 @@
/*
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 protocol
import (
"errors"
"fmt"
"sync"
"github.com/shamaton/msgpackgen/msgpack"
"github.com/sirupsen/logrus"
"git.cacert.org/cacert-gosigner/pkg/health"
"git.cacert.org/cacert-gosigner/pkg/messages"
"git.cacert.org/cacert-gosigner/pkg/x509/revoking"
)
// MsgPackHandler is a Handler implementation for the msgpack serialization format.
type MsgPackHandler struct {
logger *logrus.Logger
healthHandler *health.Handler
fetchCRLHandler *revoking.FetchCRLHandler
currentCommand *Command
currentResponse *Response
lock sync.Mutex
}
func (m *MsgPackHandler) HandleCommandAnnounce(frame []byte) error {
m.lock.Lock()
defer m.lock.Unlock()
var ann messages.CommandAnnounce
if err := msgpack.Unmarshal(frame, &ann); err != nil {
return fmt.Errorf("could not unmarshal command announcement: %w", err)
}
m.logger.WithField("announcement", &ann).Info("received command announcement")
m.currentCommand = &Command{Announce: &ann}
return nil
}
func (m *MsgPackHandler) HandleCommand(frame []byte) error {
m.lock.Lock()
defer m.lock.Unlock()
err := m.parseCommand(frame)
if err != nil {
m.currentResponse = m.buildErrorResponse(err.Error())
m.logCommandResponse()
return nil
}
err = m.handleCommand()
if err != nil {
m.logger.WithError(err).Error("command handling failed")
return err
}
m.logCommandResponse()
m.currentCommand = nil
return nil
}
func (m *MsgPackHandler) logCommandResponse() {
m.logger.WithField("command", m.currentCommand.Announce).Info("handled command")
m.logger.WithField(
"command",
m.currentCommand,
).WithField(
"response",
m.currentResponse,
).Debug("command and response")
}
func (m *MsgPackHandler) ResponseAnnounce() ([]byte, error) {
m.lock.Lock()
defer m.lock.Unlock()
announceData, err := msgpack.Marshal(m.currentResponse.Announce)
if err != nil {
return nil, fmt.Errorf("could not marshal response announcement: %w", err)
}
m.logger.WithField("announcement", m.currentResponse.Announce).Debug("write response announcement")
return announceData, nil
}
func (m *MsgPackHandler) ResponseData() ([]byte, error) {
m.lock.Lock()
defer m.lock.Unlock()
responseData, err := msgpack.Marshal(m.currentResponse.Response)
if err != nil {
return nil, fmt.Errorf("could not marshal response: %w", err)
}
m.logger.WithField("response", m.currentResponse.Response).Debug("write response")
return responseData, nil
}
func (m *MsgPackHandler) parseHealthCommand(frame []byte) error {
var command messages.HealthCommand
if err := msgpack.Unmarshal(frame, &command); err != nil {
m.logger.WithError(err).Error("unmarshal failed")
return errors.New("could not unmarshal health command")
}
m.currentCommand.Command = &command
return nil
}
func (m *MsgPackHandler) parseFetchCRLCommand(frame []byte) error {
var command messages.FetchCRLCommand
if err := msgpack.Unmarshal(frame, &command); err != nil {
m.logger.WithError(err).Error("unmarshal failed")
return errors.New("could not unmarshal fetch crl command")
}
m.currentCommand.Command = &command
return nil
}
func (m *MsgPackHandler) currentID() string {
return m.currentCommand.Announce.ID
}
func (m *MsgPackHandler) handleCommand() error {
var (
err error
responseData interface{}
responseCode messages.ResponseCode
)
switch m.currentCommand.Command.(type) {
case *messages.HealthCommand:
response, err := m.handleHealthCommand()
if err != nil {
return err
}
responseCode, responseData = messages.RespHealth, response
case *messages.FetchCRLCommand:
response, err := m.handleFetchCRLCommand()
if err != nil {
return err
}
responseCode, responseData = messages.RespFetchCRL, response
default:
return fmt.Errorf("unhandled command %s", m.currentCommand.Announce)
}
if err != nil {
return fmt.Errorf("error from command handler: %w", err)
}
m.currentResponse = &Response{
Announce: messages.BuildResponseAnnounce(responseCode, m.currentID()),
Response: responseData,
}
return nil
}
func (m *MsgPackHandler) buildErrorResponse(errMsg string) *Response {
return &Response{
Announce: messages.BuildResponseAnnounce(messages.RespError, m.currentID()),
Response: &messages.ErrorResponse{Message: errMsg},
}
}
func (m *MsgPackHandler) parseCommand(frame []byte) error {
switch m.currentCommand.Announce.Code {
case messages.CmdHealth:
return m.parseHealthCommand(frame)
case messages.CmdFetchCRL:
return m.parseFetchCRLCommand(frame)
default:
return fmt.Errorf("unhandled command code %s", m.currentCommand.Announce.Code)
}
}
func (m *MsgPackHandler) handleHealthCommand() (*messages.HealthResponse, error) {
res, err := m.healthHandler.CheckHealth()
if err != nil {
return nil, fmt.Errorf("could not check health: %w", err)
}
response := &messages.HealthResponse{
Version: res.Version,
Healthy: res.Healthy,
}
for _, info := range res.Info {
response.Info = append(response.Info, &messages.HealthInfo{
Source: info.Source,
Healthy: info.Healthy,
MoreInfo: info.MoreInfo,
})
}
return response, nil
}
func (m *MsgPackHandler) handleFetchCRLCommand() (*messages.FetchCRLResponse, error) {
fetchCRLPayload, ok := m.currentCommand.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 {
return nil, fmt.Errorf("could not fetch CRL: %w", err)
}
response := &messages.FetchCRLResponse{
IsDelta: false,
CRLNumber: res.Number,
CRLData: res.CRLData,
}
return response, nil
}
func New(logger *logrus.Logger, handlers ...RegisterHandler) (Handler, error) {
messages.RegisterGeneratedResolver()
h := &MsgPackHandler{
logger: logger,
}
for _, reg := range handlers {
reg(h)
}
return h, nil
}
type RegisterHandler func(handler *MsgPackHandler)
func RegisterHealthHandler(healthHandler *health.Handler) func(*MsgPackHandler) {
return func(h *MsgPackHandler) {
h.healthHandler = healthHandler
}
}
func RegisterFetchCRLHandler(fetchCRLHandler *revoking.FetchCRLHandler) func(handler *MsgPackHandler) {
return func(h *MsgPackHandler) {
h.fetchCRLHandler = fetchCRLHandler
}
}

@ -19,250 +19,39 @@ limitations under the License.
package protocol package protocol
import ( import (
"errors"
"fmt" "fmt"
"sync"
"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" "git.cacert.org/cacert-gosigner/pkg/messages"
) )
const CobsDelimiter = 0x00
type Command struct { type Command struct {
Announce *messages.CommandAnnounce Announce *messages.CommandAnnounce
Command interface{} Command interface{}
} }
func (c *Command) String() string {
return fmt.Sprintf("Cmd[announce={%s}, data={%s}]", c.Announce, c.Command)
}
type Response struct { type Response struct {
Announce *messages.ResponseAnnounce Announce *messages.ResponseAnnounce
Response interface{} Response interface{}
} }
func (r *Response) String() string { func (r *Response) String() string {
return fmt.Sprintf("Response[Code=%s] created=%s data=%s", r.Announce.Code, r.Announce.Created, r.Response) return fmt.Sprintf("Rsp[announce={%s}, data={%s}]", r.Announce, r.Response)
} }
// Handler is responsible for parsing incoming frames and calling commands // Handler is responsible for parsing incoming frames and calling commands
type Handler interface { type Handler interface {
// HandleCommandAnnounce handles the initial announcement of a command.
HandleCommandAnnounce([]byte) error HandleCommandAnnounce([]byte) error
// HandleCommand handles the command data.
HandleCommand([]byte) error HandleCommand([]byte) error
// ResponseAnnounce generates the announcement for a response.
ResponseAnnounce() ([]byte, error) ResponseAnnounce() ([]byte, error)
// ResponseData generates the response data.
ResponseData() ([]byte, error) ResponseData() ([]byte, error)
} }
type MsgPackHandler struct {
logger *logrus.Logger
healthHandler *health.Handler
fetchCRLHandler *revoking.FetchCRLHandler
currentCommand *Command
currentResponse *Response
lock sync.Mutex
}
func (m *MsgPackHandler) HandleCommandAnnounce(frame []byte) error {
m.lock.Lock()
defer m.lock.Unlock()
var ann messages.CommandAnnounce
if err := msgpack.Unmarshal(frame, &ann); err != nil {
return fmt.Errorf("could not unmarshal command announcement: %w", err)
}
m.logger.WithField("announcement", &ann).Info("received command announcement")
m.currentCommand = &Command{Announce: &ann}
return nil
}
func (m *MsgPackHandler) HandleCommand(frame []byte) error {
m.lock.Lock()
defer m.lock.Unlock()
var clientError error
switch m.currentCommand.Announce.Code {
case messages.CmdHealth:
// health has no payload, ignore the frame
response, err := m.handleCommand()
if err != nil {
m.logger.WithError(err).Error("health handling failed")
clientError = errors.New("could not handle request")
break
}
m.currentResponse = response
case messages.CmdFetchCRL:
var command messages.FetchCRLCommand
if err := msgpack.Unmarshal(frame, &command); err != nil {
m.logger.WithError(err).Error("unmarshal failed")
clientError = errors.New("could not unmarshal fetch crl command")
break
}
m.currentCommand.Command = command
response, err := m.handleCommand()
if err != nil {
m.logger.WithError(err).Error("fetch CRL handling failed")
clientError = errors.New("could not handle request")
break
}
m.currentResponse = response
}
if clientError != nil {
m.currentResponse = buildErrorResponse(clientError.Error())
}
m.logger.WithField(
"command",
m.currentCommand,
).WithField(
"response",
m.currentResponse,
).Info("handled command")
m.currentCommand = nil
return nil
}
func (m *MsgPackHandler) ResponseAnnounce() ([]byte, error) {
m.lock.Lock()
defer m.lock.Unlock()
announceData, err := msgpack.Marshal(m.currentResponse.Announce)
if err != nil {
return nil, fmt.Errorf("could not marshal response announcement: %w", err)
}
m.logger.WithField("announcement", &m.currentResponse.Announce).Info("write response announcement")
return announceData, nil
}
func (m *MsgPackHandler) ResponseData() ([]byte, error) {
m.lock.Lock()
defer m.lock.Unlock()
responseData, err := msgpack.Marshal(m.currentResponse.Response)
if err != nil {
return nil, fmt.Errorf("could not marshal response: %w", err)
}
m.logger.WithField("response", &m.currentResponse.Response).Info("write response")
return responseData, nil
}
func (m *MsgPackHandler) handleCommand() (*Response, error) {
var (
err error
responseData interface{}
responseCode messages.ResponseCode
)
switch m.currentCommand.Announce.Code {
case messages.CmdHealth:
var res *health.Result
res, err = m.healthHandler.CheckHealth()
if err != nil {
return nil, err
}
response := &messages.HealthResponse{
Version: res.Version,
Healthy: res.Healthy,
}
for _, info := range res.Info {
response.Info = append(response.Info, &messages.HealthInfo{
Source: info.Source,
Healthy: info.Healthy,
MoreInfo: info.MoreInfo,
})
}
responseCode, responseData = messages.RespHealth, response
case messages.CmdFetchCRL:
var res *revoking.Result
fetchCRLPayload, ok := m.currentCommand.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 {
return nil, err
}
response := &messages.FetchCRLResponse{
IsDelta: false,
CRLData: res.Data,
}
responseCode, responseData = messages.RespFetchCRL, response
default:
return nil, fmt.Errorf("unhandled command %s", m.currentCommand.Announce)
}
if err != nil {
return nil, fmt.Errorf("error from command handler: %w", err)
}
return &Response{
Announce: messages.BuildResponseAnnounce(responseCode),
Response: responseData,
}, nil
}
func buildErrorResponse(errMsg string) *Response {
return &Response{
Announce: messages.BuildResponseAnnounce(messages.RespError),
Response: &messages.ErrorResponse{Message: errMsg},
}
}
func New(logger *logrus.Logger, handlers ...RegisterHandler) (Handler, error) {
messages.RegisterGeneratedResolver()
h := &MsgPackHandler{
logger: logger,
}
for _, reg := range handlers {
reg(h)
}
return h, nil
}
type RegisterHandler func(handler *MsgPackHandler)
func RegisterHealthHandler(healthHandler *health.Handler) func(*MsgPackHandler) {
return func(h *MsgPackHandler) {
h.healthHandler = healthHandler
}
}
func RegisterFetchCRLHandler(fetchCRLHandler *revoking.FetchCRLHandler) func(handler *MsgPackHandler) {
return func(h *MsgPackHandler) {
h.fetchCRLHandler = fetchCRLHandler
}
}

@ -95,7 +95,7 @@ func (h *Handler) Close() error {
return nil return nil
} }
var cobsConfig = cobs.Config{SpecialByte: 0x00, Delimiter: true, EndingSave: true} var cobsConfig = cobs.Config{SpecialByte: protocol.CobsDelimiter, Delimiter: true, EndingSave: true}
func (h *Handler) Run(ctx context.Context) error { func (h *Handler) Run(ctx context.Context) error {
h.protocolState = cmdAnnounce h.protocolState = cmdAnnounce
@ -133,7 +133,9 @@ func (h *Handler) readFrames() error {
) )
var frame []byte var frame []byte
buffer := &bytes.Buffer{} buffer := &bytes.Buffer{}
delimiter := []byte{cobsConfig.SpecialByte} delimiter := []byte{cobsConfig.SpecialByte}
for { for {
@ -212,6 +214,9 @@ func (h *Handler) nextState() error {
func (h *Handler) handleProtocolState() error { func (h *Handler) handleProtocolState() error {
h.logger.Tracef("handling protocol state %s", h.protocolState) h.logger.Tracef("handling protocol state %s", h.protocolState)
h.lock.Lock()
defer h.lock.Unlock()
switch h.protocolState { switch h.protocolState {
case cmdAnnounce: case cmdAnnounce:
if err := h.handleCmdAnnounce(); err != nil { if err := h.handleCmdAnnounce(); err != nil {
@ -237,9 +242,6 @@ func (h *Handler) handleProtocolState() error {
} }
func (h *Handler) writeToPort(data []byte) error { func (h *Handler) writeToPort(data []byte) error {
h.lock.Lock()
defer h.lock.Unlock()
reader := bytes.NewReader(data) reader := bytes.NewReader(data)
n, err := io.Copy(h.port, reader) n, err := io.Copy(h.port, reader)
@ -249,10 +251,6 @@ func (h *Handler) writeToPort(data []byte) error {
h.logger.Tracef("wrote %d bytes", n) h.logger.Tracef("wrote %d bytes", n)
if err := h.port.Flush(); err != nil {
return fmt.Errorf("could not flush data: %w", err)
}
return nil return nil
} }
@ -272,19 +270,17 @@ func (h *Handler) readFromPort() ([]byte, error) {
func (h *Handler) handleCmdAnnounce() error { func (h *Handler) handleCmdAnnounce() error {
h.logger.Trace("waiting for command announce") h.logger.Trace("waiting for command announce")
select { frame := <-h.framesIn
case frame := <-h.framesIn: if frame == nil {
if frame == nil { return nil
return nil }
}
if err := h.protocolHandler.HandleCommandAnnounce(frame); err != nil { if err := h.protocolHandler.HandleCommandAnnounce(frame); err != nil {
return fmt.Errorf("command announce handling failed: %w", err) return fmt.Errorf("command announce handling failed: %w", err)
} }
if err := h.nextState(); err != nil { if err := h.nextState(); err != nil {
return err return err
}
} }
return nil return nil
@ -293,20 +289,18 @@ func (h *Handler) handleCmdAnnounce() error {
func (h *Handler) handleCmdData() error { func (h *Handler) handleCmdData() error {
h.logger.Trace("waiting for command data") h.logger.Trace("waiting for command data")
select { frame := <-h.framesIn
case frame := <-h.framesIn:
if frame == nil { if frame == nil {
return nil return nil
} }
if err := h.protocolHandler.HandleCommand(frame); err != nil { if err := h.protocolHandler.HandleCommand(frame); err != nil {
return fmt.Errorf("command handler failed: %w", err) return fmt.Errorf("command handler failed: %w", err)
} }
if err := h.nextState(); err != nil { if err := h.nextState(); err != nil {
return err return err
}
} }
return nil return nil
@ -318,8 +312,6 @@ func (h *Handler) handleRespAnnounce() error {
return fmt.Errorf("could not get response announcement: %w", err) return fmt.Errorf("could not get response announcement: %w", err)
} }
h.logger.Trace("writing response announce")
if err := h.writeFrame(frame); err != nil { if err := h.writeFrame(frame); err != nil {
return err return err
} }
@ -337,8 +329,6 @@ func (h *Handler) handleRespData() error {
return fmt.Errorf("could not get response data: %w", err) return fmt.Errorf("could not get response data: %w", err)
} }
h.logger.Trace("writing response data")
if err := h.writeFrame(frame); err != nil { if err := h.writeFrame(frame); err != nil {
return err return err
} }
@ -354,7 +344,7 @@ func New(cfg *config.Serial, logger *logrus.Logger, protocolHandler protocol.Han
h := &Handler{ h := &Handler{
protocolHandler: protocolHandler, protocolHandler: protocolHandler,
logger: logger, logger: logger,
framesIn: make(chan []byte, 0), framesIn: make(chan []byte),
} }
h.config = &serial.Config{Name: cfg.Device, Baud: cfg.Baud, ReadTimeout: cfg.Timeout} h.config = &serial.Config{Name: cfg.Device, Baud: cfg.Baud, ReadTimeout: cfg.Timeout}

@ -108,7 +108,8 @@ func NewRevokeCertificate(serialNumber *big.Int, reason CRLReason) *RevokeCertif
} }
type CRLInformation struct { type CRLInformation struct {
CRL []byte // DER encoded CRL CRL []byte // DER encoded CRL
Number *big.Int
} }
func (r *X509Revoking) Revoke(revokeCertificate *RevokeCertificate) (*pkix.RevokedCertificate, error) { func (r *X509Revoking) Revoke(revokeCertificate *RevokeCertificate) (*pkix.RevokedCertificate, error) {
@ -146,7 +147,7 @@ func (r *X509Revoking) CreateCRL() (*CRLInformation, error) {
return nil, fmt.Errorf("could not sign revocation list: %w", err) return nil, fmt.Errorf("could not sign revocation list: %w", err)
} }
return &CRLInformation{CRL: list}, nil return &CRLInformation{CRL: list, Number: nextNumber}, nil
} }
func NewX509Revoking( func NewX509Revoking(
@ -159,7 +160,8 @@ func NewX509Revoking(
} }
type Result struct { type Result struct {
Data []byte CRLData []byte
Number *big.Int
} }
type FetchCRLHandler struct { type FetchCRLHandler struct {
@ -181,5 +183,5 @@ func (h *FetchCRLHandler) FetchCRL(issuerID string) (*Result, error) {
return nil, fmt.Errorf("could not create CRL for issuer ID %s: %w", issuerID, err) return nil, fmt.Errorf("could not create CRL for issuer ID %s: %w", issuerID, err)
} }
return &Result{Data: currentCRL.CRL}, nil return &Result{CRLData: currentCRL.CRL, Number: currentCRL.Number}, nil
} }

Loading…
Cancel
Save