diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1559b64 --- /dev/null +++ b/Makefile @@ -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 \ No newline at end of file diff --git a/cmd/clientsim/main.go b/cmd/clientsim/main.go index 8027487..5a9309c 100644 --- a/cmd/clientsim/main.go +++ b/cmd/clientsim/main.go @@ -37,7 +37,7 @@ import ( "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 @@ -82,17 +82,16 @@ func (g *TestCommandGenerator) CmdAnnouncement() ([]byte, error) { g.lock.Lock() defer g.lock.Unlock() - select { - 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.currentCommand = <-g.commands - g.logger.WithField("announcement", &g.currentCommand.Announce).Info("write command announcement") - - return announceData, nil + 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") + + return announceData, nil } func (g *TestCommandGenerator) CmdData() ([]byte, error) { @@ -138,13 +137,15 @@ func (g *TestCommandGenerator) HandleResponse(frame []byte) error { return fmt.Errorf("unmarshal failed: %w", err) } - g.currentResponse.Response = response + g.currentResponse.Response = &response case messages.RespFetchCRL: var response messages.FetchCRLResponse if err := msgpack.Unmarshal(frame, &response); err != nil { return fmt.Errorf("unmarshal failed: %w", err) } + + g.currentResponse.Response = &response } g.logger.WithField( @@ -159,14 +160,27 @@ func (g *TestCommandGenerator) HandleResponse(frame []byte) 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") - 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{ - Announce: messages.BuildCommandAnnounce(messages.CmdFetchCRL), + Announce: announce, Command: &messages.FetchCRLCommand{IssuerID: "sub-ecc_person_2022"}, } @@ -181,8 +195,13 @@ func (g *TestCommandGenerator) GenerateCommands(ctx context.Context) error { return nil 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{ - Announce: messages.BuildCommandAnnounce(messages.CmdHealth), + Announce: announce, Command: &messages.HealthCommand{}, } } @@ -203,7 +222,9 @@ func (c *clientSimulator) readFrames() error { const readInterval = 50 * time.Millisecond var frame []byte + buffer := &bytes.Buffer{} + delimiter := []byte{cobsConfig.SpecialByte} for { @@ -231,6 +252,8 @@ func (c *clientSimulator) readFrames() error { rest := buffer.Bytes() if !bytes.Contains(rest, delimiter) { + c.logger.Tracef("read data does not contain the delimiter %x", delimiter) + continue } @@ -254,6 +277,8 @@ func (c *clientSimulator) readFrames() error { c.logger.Tracef("frame decoded to length %d", len(decoded)) c.framesIn <- decoded + + c.logger.Tracef("%d bytes remaining", len(rest)) } buffer.Truncate(0) @@ -266,9 +291,6 @@ func (c *clientSimulator) readFrames() error { func (c *clientSimulator) writeFrame(frame []byte) error { encoded := cobs.Encode(frame, cobsConfig) - c.lock.Lock() - defer c.lock.Unlock() - if _, err := io.Copy(os.Stdout, bytes.NewBuffer(encoded)); err != nil { return fmt.Errorf("could not write data: %w", err) } @@ -281,11 +303,15 @@ func (c *clientSimulator) readFromStdin() ([]byte, error) { buf := make([]byte, bufferSize) + c.logger.Trace("waiting for input") + count, err := os.Stdin.Read(buf) if err != nil { return nil, fmt.Errorf("reading input failed: %w", err) } + c.logger.Tracef("read %d bytes from stdin", count) + return buf[:count], nil } @@ -308,25 +334,6 @@ func (c *clientSimulator) writeCmdAnnouncement() error { 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 { frame, err := c.commandGenerator.CmdData() if err != nil { @@ -349,19 +356,18 @@ func (c *clientSimulator) writeCommand() error { func (c *clientSimulator) handleResponseAnnounce() error { c.logger.Trace("waiting for response announce") - select { - case frame := <-c.framesIn: - if frame == nil { - return nil - } + frame := <-c.framesIn - if err := c.commandGenerator.HandleResponseAnnounce(frame); err != nil { - return fmt.Errorf("response announce handling failed: %w", err) - } + if frame == nil { + return nil + } - if err := c.nextState(); err != nil { - return err - } + if err := c.commandGenerator.HandleResponseAnnounce(frame); err != nil { + return fmt.Errorf("response announce handling failed: %w", err) + } + + if err := c.nextState(); err != nil { + return err } return nil @@ -370,19 +376,18 @@ func (c *clientSimulator) handleResponseAnnounce() error { func (c *clientSimulator) handleResponseData() error { c.logger.Trace("waiting for response data") - select { - case frame := <-c.framesIn: - if frame == nil { - return nil - } + frame := <-c.framesIn - if err := c.commandGenerator.HandleResponse(frame); err != nil { - return fmt.Errorf("response handler failed: %w", err) - } + if frame == nil { + return nil + } - if err := c.nextState(); err != nil { - return err - } + if err := c.commandGenerator.HandleResponse(frame); err != nil { + return fmt.Errorf("response handler failed: %w", err) + } + + if err := c.nextState(); err != nil { + return err } return nil @@ -412,6 +417,7 @@ func (c *clientSimulator) Run(ctx context.Context) error { if err != nil { return fmt.Errorf("error from handler loop: %w", err) } + return nil default: if err := c.handleProtocolState(); err != nil { @@ -424,6 +430,9 @@ func (c *clientSimulator) Run(ctx context.Context) error { func (c *clientSimulator) handleProtocolState() error { c.logger.Tracef("handling protocol state %s", c.protocolState) + c.lock.Lock() + defer c.lock.Unlock() + switch c.protocolState { case cmdAnnounce: if err := c.writeCmdAnnouncement(); err != nil { @@ -462,17 +471,17 @@ func (c *clientSimulator) nextState() error { func main() { logger := logrus.New() logger.SetOutput(os.Stderr) - logger.SetLevel(logrus.TraceLevel) + logger.SetLevel(logrus.DebugLevel) messages.RegisterGeneratedResolver() sim := &clientSimulator{ commandGenerator: &TestCommandGenerator{ logger: logger, - commands: make(chan *protocol.Command, 0), + commands: make(chan *protocol.Command), }, logger: logger, - framesIn: make(chan []byte, 0), + framesIn: make(chan []byte), } err := sim.Run(context.Background()) diff --git a/cmd/signer/main.go b/cmd/signer/main.go index c0296d6..c5c7436 100644 --- a/cmd/signer/main.go +++ b/cmd/signer/main.go @@ -35,9 +35,9 @@ import ( ) var ( - commit string - date string - version string + commit = "dev" + date = "unknown" + version = "unknown" ) const ( diff --git a/go.mod b/go.mod index cb8e819..95661e2 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ go 1.17 require ( 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/shamaton/msgpackgen v0.3.0 github.com/sirupsen/logrus v1.9.0 @@ -14,7 +16,6 @@ require ( ) require ( - github.com/dave/jennifer v1.4.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 481e99e..dc95337 100644 --- a/go.sum +++ b/go.sum @@ -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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/go.mod h1:L0d+EbGirv6IzsXNzwULduI2/z3ijkkAmsAuPMpLfqA= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= diff --git a/pkg/messages/messages.go b/pkg/messages/messages.go index 2580b56..1523713 100644 --- a/pkg/messages/messages.go +++ b/pkg/messages/messages.go @@ -24,8 +24,14 @@ import ( "crypto/x509" "encoding/pem" "fmt" + "math/big" "strings" "time" + + // required for msgpackgen + _ "github.com/dave/jennifer" + + "github.com/google/uuid" ) type CommandCode int8 @@ -72,33 +78,48 @@ func (c ResponseCode) String() string { type CommandAnnounce struct { Code CommandCode `msgpack:"code"` + ID string `msgpack:"id"` Created time.Time `msgpack:"created"` } 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 { Code ResponseCode `msgpack:"code"` Created time.Time `msgpack:"created"` + ID string `msgpack:"id"` } 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 { - 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 + IssuerID string `msgpack:"issuer_id"` + LastKnownID *big.Int `msgpack:"last_known_id"` +} + +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 { } +func (h *HealthCommand) String() string { + return "" +} + type HealthInfo struct { Source string Healthy bool @@ -138,9 +159,10 @@ func (h *HealthResponse) String() string { } type FetchCRLResponse struct { - IssuerID string `msgpack:"issuer_id"` - IsDelta bool `msgpack:"is_delta"` - CRLData []byte `msgpack:"crl_data"` + IssuerID string `msgpack:"issuer_id"` + IsDelta bool `msgpack:"is_delta"` + CRLData []byte `msgpack:"crl_data"` + CRLNumber *big.Int } func (r *FetchCRLResponse) String() string { @@ -151,12 +173,18 @@ func (r *FetchCRLResponse) String() string { if r.IsDelta { _, _ = fmt.Fprint(builder, ", delta CRL data not shown") } else { - revlist, err := x509.ParseRevocationList(r.CRLData) + revocationList, 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)) + _, _ = fmt.Fprintf( + 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") _ = pem.Encode(builder, &pem.Block{ Type: "CERTIFICATE REVOCATION LIST", @@ -172,10 +200,19 @@ type ErrorResponse struct { Message string `msgpack:"message"` } -func BuildCommandAnnounce(code CommandCode) *CommandAnnounce { - return &CommandAnnounce{Code: code, Created: time.Now().UTC()} +func (e *ErrorResponse) String() string { + return fmt.Sprintf("message=%s", e.Message) } -func BuildResponseAnnounce(code ResponseCode) *ResponseAnnounce { - return &ResponseAnnounce{Code: code, Created: time.Now().UTC()} +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, commandID string) *ResponseAnnounce { + return &ResponseAnnounce{Code: code, ID: commandID, Created: time.Now().UTC()} } diff --git a/pkg/messages/resolver.msgpackgen.go b/pkg/messages/resolver.msgpackgen.go index 091da6c..7180b8b 100644 --- a/pkg/messages/resolver.msgpackgen.go +++ b/pkg/messages/resolver.msgpackgen.go @@ -116,36 +116,6 @@ 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) @@ -273,36 +243,6 @@ 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) @@ -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, 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) @@ -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, 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) @@ -1057,217 +969,6 @@ func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f 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 func ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder) (int, error) { size := 0 diff --git a/pkg/protocol/msgpack.go b/pkg/protocol/msgpack.go new file mode 100644 index 0000000..dc5102b --- /dev/null +++ b/pkg/protocol/msgpack.go @@ -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 + } +} diff --git a/pkg/protocol/protocol.go b/pkg/protocol/protocol.go index d97ea21..e2b5216 100644 --- a/pkg/protocol/protocol.go +++ b/pkg/protocol/protocol.go @@ -19,250 +19,39 @@ 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/x509/revoking" - - "git.cacert.org/cacert-gosigner/pkg/health" "git.cacert.org/cacert-gosigner/pkg/messages" ) +const CobsDelimiter = 0x00 + type Command struct { Announce *messages.CommandAnnounce Command interface{} } +func (c *Command) String() string { + return fmt.Sprintf("Cmd[announce={%s}, data={%s}]", c.Announce, c.Command) +} + 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) + return fmt.Sprintf("Rsp[announce={%s}, data={%s}]", r.Announce, r.Response) } // Handler is responsible for parsing incoming frames and calling commands type Handler interface { + // HandleCommandAnnounce handles the initial announcement of a command. HandleCommandAnnounce([]byte) error + // HandleCommand handles the command data. HandleCommand([]byte) error + // ResponseAnnounce generates the announcement for a response. ResponseAnnounce() ([]byte, error) + // ResponseData generates the response data. 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 - } -} diff --git a/pkg/seriallink/seriallink.go b/pkg/seriallink/seriallink.go index b9acb77..49bf3ed 100644 --- a/pkg/seriallink/seriallink.go +++ b/pkg/seriallink/seriallink.go @@ -95,7 +95,7 @@ func (h *Handler) Close() error { 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 { h.protocolState = cmdAnnounce @@ -133,7 +133,9 @@ func (h *Handler) readFrames() error { ) var frame []byte + buffer := &bytes.Buffer{} + delimiter := []byte{cobsConfig.SpecialByte} for { @@ -212,6 +214,9 @@ func (h *Handler) nextState() error { func (h *Handler) handleProtocolState() error { h.logger.Tracef("handling protocol state %s", h.protocolState) + h.lock.Lock() + defer h.lock.Unlock() + switch h.protocolState { case cmdAnnounce: if err := h.handleCmdAnnounce(); err != nil { @@ -237,9 +242,6 @@ func (h *Handler) handleProtocolState() error { } func (h *Handler) writeToPort(data []byte) error { - h.lock.Lock() - defer h.lock.Unlock() - reader := bytes.NewReader(data) 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) - if err := h.port.Flush(); err != nil { - return fmt.Errorf("could not flush data: %w", err) - } - return nil } @@ -272,19 +270,17 @@ func (h *Handler) readFromPort() ([]byte, error) { func (h *Handler) handleCmdAnnounce() error { h.logger.Trace("waiting for command announce") - select { - case frame := <-h.framesIn: - if frame == nil { - return nil - } + frame := <-h.framesIn + if frame == nil { + return nil + } - if err := h.protocolHandler.HandleCommandAnnounce(frame); err != nil { - return fmt.Errorf("command announce handling failed: %w", err) - } + if err := h.protocolHandler.HandleCommandAnnounce(frame); err != nil { + return fmt.Errorf("command announce handling failed: %w", err) + } - if err := h.nextState(); err != nil { - return err - } + if err := h.nextState(); err != nil { + return err } return nil @@ -293,20 +289,18 @@ func (h *Handler) handleCmdAnnounce() error { func (h *Handler) handleCmdData() error { h.logger.Trace("waiting for command data") - select { - case frame := <-h.framesIn: + frame := <-h.framesIn - if frame == nil { - return nil - } + if frame == nil { + return nil + } - if err := h.protocolHandler.HandleCommand(frame); err != nil { - return fmt.Errorf("command handler failed: %w", err) - } + if err := h.protocolHandler.HandleCommand(frame); err != nil { + return fmt.Errorf("command handler failed: %w", err) + } - if err := h.nextState(); err != nil { - return err - } + if err := h.nextState(); err != nil { + return err } return nil @@ -318,8 +312,6 @@ func (h *Handler) handleRespAnnounce() error { return fmt.Errorf("could not get response announcement: %w", err) } - h.logger.Trace("writing response announce") - if err := h.writeFrame(frame); err != nil { return err } @@ -337,8 +329,6 @@ func (h *Handler) handleRespData() error { return fmt.Errorf("could not get response data: %w", err) } - h.logger.Trace("writing response data") - if err := h.writeFrame(frame); err != nil { return err } @@ -354,7 +344,7 @@ func New(cfg *config.Serial, logger *logrus.Logger, protocolHandler protocol.Han h := &Handler{ protocolHandler: protocolHandler, logger: logger, - framesIn: make(chan []byte, 0), + framesIn: make(chan []byte), } h.config = &serial.Config{Name: cfg.Device, Baud: cfg.Baud, ReadTimeout: cfg.Timeout} diff --git a/pkg/x509/revoking/revoking.go b/pkg/x509/revoking/revoking.go index 79923a2..158ab67 100644 --- a/pkg/x509/revoking/revoking.go +++ b/pkg/x509/revoking/revoking.go @@ -108,7 +108,8 @@ func NewRevokeCertificate(serialNumber *big.Int, reason CRLReason) *RevokeCertif } 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) { @@ -146,7 +147,7 @@ func (r *X509Revoking) CreateCRL() (*CRLInformation, error) { 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( @@ -159,7 +160,8 @@ func NewX509Revoking( } type Result struct { - Data []byte + CRLData []byte + Number *big.Int } 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 &Result{Data: currentCRL.CRL}, nil + return &Result{CRLData: currentCRL.CRL, Number: currentCRL.Number}, nil }