From afe7d23c9b6f480e439f7ad04eec05fdc8661d3a Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 2 Dec 2022 18:31:59 +0100 Subject: [PATCH] Implement CA information command This commit defines command codes for planned commands and response codes for their corresponding responses. The health response from the HSM access component has been reduced to avoid unnecessary data transmissions. A new CA information command has been implemented. This command can be used to retrieve the CA certificate and profile information for a given CA name. The client simulator has been updated to retrieve CA information for all CAs when the list of CAs changes. --- cmd/clientsim/main.go | 73 ++++++++++- cmd/signer/main.go | 1 + internal/cainfo/cainfo.go | 29 +++++ internal/handler/msgpack.go | 59 ++++++++- internal/hsm/hsm.go | 135 ++++++++++---------- pkg/messages/messages.go | 78 ++++++------ pkg/messages/messages_test.go | 142 ++++++++------------- pkg/messages/resolver.msgpackgen.go | 189 ++++++++++++++++++++++++++++ 8 files changed, 507 insertions(+), 199 deletions(-) create mode 100644 internal/cainfo/cainfo.go diff --git a/cmd/clientsim/main.go b/cmd/clientsim/main.go index fdac7ca..ed090d3 100644 --- a/cmd/clientsim/main.go +++ b/cmd/clientsim/main.go @@ -22,9 +22,11 @@ package main import ( "context" "crypto/rand" + "crypto/x509" "fmt" "io" "os" + "sort" "time" "github.com/shamaton/msgpackgen/msgpack" @@ -167,7 +169,9 @@ func (c *clientSimulator) Run(ctx context.Context) error { } type ClientHandler struct { - logger *logrus.Logger + logger *logrus.Logger + commands chan *protocol.Command + caList []string } func (c *ClientHandler) Send(ctx context.Context, command *protocol.Command, out chan []byte) error { @@ -244,6 +248,29 @@ func (c *ClientHandler) ResponseData(ctx context.Context, in chan []byte, respon return fmt.Errorf("could not unmarshal health response data: %w", err) } + c.updateCAs(ctx, c.commands, resp.Info) + + response.Response = &resp + case messages.RespCAInfo: + var resp messages.CAInfoResponse + if err := msgpack.Unmarshal(frame, &resp); err != nil { + return fmt.Errorf("could not unmarshal CA info response data: %w", err) + } + + certificate, err := x509.ParseCertificate(resp.Certificate) + if err != nil { + return fmt.Errorf("could not parse certificate data: %w", err) + } + + c.logger.Infof( + "certificate for %s: subject=%s, issuer=%s, serial=0x%x, valid from %s to %s", + resp.Name, + certificate.Subject, + certificate.Issuer, + certificate.SerialNumber, + certificate.NotBefore, + certificate.NotAfter) + response.Response = &resp case messages.RespFetchCRL: var resp messages.FetchCRLResponse @@ -269,8 +296,40 @@ func (c *ClientHandler) HandleResponse(_ context.Context, response *protocol.Res return nil } -func newClientHandler(logger *logrus.Logger) *ClientHandler { - return &ClientHandler{logger: logger} +func (c *ClientHandler) updateCAs(ctx context.Context, out chan *protocol.Command, info []*messages.HealthInfo) { + caList := make([]string, 0) + + for _, i := range info { + if i.Source == "HSM" { + c.logger.Debugf("info from HSM: %s", i) + + for caName := range i.MoreInfo { + caList = append(caList, caName) + } + } + } + + sort.Strings(caList) + + if len(caList) != len(c.caList) { + c.caList = caList + + for _, ca := range c.caList { + select { + case <-ctx.Done(): + return + case out <- &protocol.Command{ + Announce: messages.BuildCommandAnnounce(messages.CmdCAInfo), + Command: &messages.CAInfoCommand{Name: ca}, + }: + continue + } + } + } +} + +func newClientHandler(logger *logrus.Logger, commands chan *protocol.Command) *ClientHandler { + return &ClientHandler{logger: logger, commands: commands} } func main() { @@ -285,16 +344,20 @@ func main() { logger.WithError(err).Fatal("could not create COBS framer") } + commandBufferSize := 50 + + commandCh := make(chan *protocol.Command, commandBufferSize) + sim := &clientSimulator{ commandGenerator: &TestCommandGenerator{ logger: logger, - commands: make(chan *protocol.Command), + commands: commandCh, }, logger: logger, framesIn: make(chan []byte), framesOut: make(chan []byte), framer: cobsFramer, - clientHandler: newClientHandler(logger), + clientHandler: newClientHandler(logger, commandCh), } err = sim.Run(context.Background()) diff --git a/cmd/signer/main.go b/cmd/signer/main.go index d4ec95c..68943f1 100644 --- a/cmd/signer/main.go +++ b/cmd/signer/main.go @@ -105,6 +105,7 @@ func main() { logger, handler.RegisterHealthHandler(healthHandler), handler.RegisterFetchCRLHandler(fetchCRLHandler), + handler.RegisterCAInfoHandler(access), ) if err != nil { logger.WithError(err).Fatal("could not setup protocol handler") diff --git a/internal/cainfo/cainfo.go b/internal/cainfo/cainfo.go new file mode 100644 index 0000000..60edfad --- /dev/null +++ b/internal/cainfo/cainfo.go @@ -0,0 +1,29 @@ +/* +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 cainfo + +import "git.cacert.org/cacert-gosigner/pkg/messages" + +type Result struct { + Certificate []byte + Profiles []messages.CAProfile +} + +type Handler interface { + GetCAInfo(string) (*Result, error) +} diff --git a/internal/handler/msgpack.go b/internal/handler/msgpack.go index 23d0357..2963b92 100644 --- a/internal/handler/msgpack.go +++ b/internal/handler/msgpack.go @@ -27,11 +27,11 @@ import ( "github.com/shamaton/msgpackgen/msgpack" "github.com/sirupsen/logrus" - "git.cacert.org/cacert-gosigner/pkg/protocol" - + "git.cacert.org/cacert-gosigner/internal/cainfo" "git.cacert.org/cacert-gosigner/internal/health" "git.cacert.org/cacert-gosigner/internal/x509/revoking" "git.cacert.org/cacert-gosigner/pkg/messages" + "git.cacert.org/cacert-gosigner/pkg/protocol" ) const readCommandTimeOut = 5 * time.Second @@ -40,9 +40,10 @@ var errReadCommandTimeout = errors.New("read command timeout expired") // MsgPackHandler is a ServerHandler implementation for the msgpack serialization format. type MsgPackHandler struct { - logger *logrus.Logger - healthHandler *health.Handler - fetchCRLHandler *revoking.FetchCRLHandler + logger *logrus.Logger + healthHandler *health.Handler + certificateAuthorityInfoHandler cainfo.Handler + fetchCRLHandler *revoking.FetchCRLHandler } func (m *MsgPackHandler) CommandAnnounce(ctx context.Context, frames chan []byte) (*protocol.Command, error) { @@ -149,6 +150,18 @@ func (m *MsgPackHandler) parseHealthCommand(frame []byte) (*messages.HealthComma return &command, nil } +func (m *MsgPackHandler) parseCAInfoCommand(frame []byte) (*messages.CAInfoCommand, error) { + var command messages.CAInfoCommand + + if err := msgpack.Unmarshal(frame, &command); err != nil { + m.logger.WithError(err).Error("unmarshal failed") + + return nil, errors.New("could not unmarshal CA info command") + } + + return &command, nil +} + func (m *MsgPackHandler) parseFetchCRLCommand(frame []byte) (*messages.FetchCRLCommand, error) { var command messages.FetchCRLCommand @@ -175,6 +188,13 @@ func (m *MsgPackHandler) handleCommand(command *protocol.Command) (*protocol.Res } responseCode, responseData = messages.RespHealth, response + case *messages.CAInfoCommand: + response, err := m.handleCAInfoCommand(cmd) + if err != nil { + return nil, err + } + + responseCode, responseData = messages.RespCAInfo, response case *messages.FetchCRLCommand: response, err := m.handleFetchCRLCommand(cmd) if err != nil { @@ -208,6 +228,13 @@ func (m *MsgPackHandler) parseCommand(frame []byte, command *protocol.Command) e } command.Command = healthCommand + case messages.CmdCAInfo: + caInfoCommand, err := m.parseCAInfoCommand(frame) + if err != nil { + return err + } + + command.Command = caInfoCommand case messages.CmdFetchCRL: fetchCRLCommand, err := m.parseFetchCRLCommand(frame) if err != nil { @@ -244,6 +271,22 @@ func (m *MsgPackHandler) handleHealthCommand() (*messages.HealthResponse, error) return response, nil } +func (m *MsgPackHandler) handleCAInfoCommand(command *messages.CAInfoCommand) (*messages.CAInfoResponse, error) { + res, err := m.certificateAuthorityInfoHandler.GetCAInfo(command.Name) + if err != nil { + return nil, fmt.Errorf("could not get CA information") + } + + response := &messages.CAInfoResponse{ + Name: command.Name, + Certificate: res.Certificate, + Signing: res.Certificate != nil && len(res.Profiles) > 0, + Profiles: res.Profiles, + } + + return response, nil +} + func (m *MsgPackHandler) handleFetchCRLCommand(command *messages.FetchCRLCommand) (*messages.FetchCRLResponse, error) { var crlNumber *big.Int @@ -299,3 +342,9 @@ func RegisterFetchCRLHandler(fetchCRLHandler *revoking.FetchCRLHandler) func(han h.fetchCRLHandler = fetchCRLHandler } } + +func RegisterCAInfoHandler(caInfoHandler cainfo.Handler) func(handler *MsgPackHandler) { + return func(h *MsgPackHandler) { + h.certificateAuthorityInfoHandler = caInfoHandler + } +} diff --git a/internal/hsm/hsm.go b/internal/hsm/hsm.go index b8fafa3..b18cdb3 100644 --- a/internal/hsm/hsm.go +++ b/internal/hsm/hsm.go @@ -36,10 +36,10 @@ import ( "github.com/ThalesIgnite/crypto11" "github.com/sirupsen/logrus" - "git.cacert.org/cacert-gosigner/pkg/messages" - + "git.cacert.org/cacert-gosigner/internal/cainfo" "git.cacert.org/cacert-gosigner/internal/config" "git.cacert.org/cacert-gosigner/internal/health" + "git.cacert.org/cacert-gosigner/pkg/messages" ) var ( @@ -55,6 +55,56 @@ type caFile struct { label string } +func (c *caFile) buildCertificatePath(caDirectory string) string { + fileName := c.sc.CertificateFileName(c.label) + + if caDirectory == "" { + return fileName + } + + return path.Join(caDirectory, fileName) +} + +func (c *caFile) loadCertificate(caDirectory string) (*x509.Certificate, error) { + certFile := c.buildCertificatePath(caDirectory) + + certFileInfo, err := os.Stat(certFile) + if err != nil { + if errors.Is(err, syscall.ENOENT) { + return nil, nil + } + + return nil, fmt.Errorf("could not get info for %s: %w", certFile, err) + } + + if !certFileInfo.Mode().IsRegular() { + return nil, fmt.Errorf("certificate file %s is not a regular file", certFile) + } + + certData, err := os.ReadFile(certFile) + if err != nil { + return nil, fmt.Errorf("could not read %s: %w", certFile, err) + } + + certificate, err := x509.ParseCertificate(certData) + if err != nil { + return nil, fmt.Errorf("could not parse certificate from %s: %w", certFile, err) + } + + return certificate, nil +} + +func (c *caFile) storeCertificate(caDirectory string, certificate []byte) error { + certFile := c.buildCertificatePath(caDirectory) + + err := os.WriteFile(certFile, certificate, 0o600) + if err != nil { + return fmt.Errorf("could not write certificate file %s: %w", certFile, err) + } + + return nil +} + type Access struct { logger *logrus.Logger caDirectory string @@ -70,33 +120,24 @@ func (a *Access) Healthy() (*health.Info, error) { moreInfo := make(map[string]string) for _, ca := range a.signerConfig.RootCAs() { - infoKey := fmt.Sprintf("root-%s", ca) - - cert, err := a.GetRootCACertificate(ca) + _, err := a.GetRootCACertificate(ca) if err != nil { healthy = false - moreInfo[infoKey] = messages.CertificateInfoFailed.String() + moreInfo[ca] = string(messages.CertStatusFailed) continue } - moreInfo[infoKey] = messages.CertificateInfo{ - Status: messages.CertStatusOk, - Signing: false, - Profiles: []messages.CAProfile{}, - ValidUntil: cert.NotAfter.UTC(), - }.String() + moreInfo[ca] = string(messages.CertStatusOk) } for _, ca := range a.signerConfig.SubordinateCAs() { - infoKey := fmt.Sprintf("sub-%s", ca) - - cert, err := a.GetSubordinateCACertificate(ca) + _, err := a.GetSubordinateCACertificate(ca) if err != nil { healthy = false - moreInfo[infoKey] = messages.CertificateInfoFailed.String() + moreInfo[ca] = string(messages.CertStatusFailed) continue } @@ -105,7 +146,7 @@ func (a *Access) Healthy() (*health.Info, error) { if err != nil { healthy = false - moreInfo[infoKey] = messages.CertificateInfoFailed.String() + moreInfo[ca] = string(messages.CertStatusFailed) continue } @@ -114,17 +155,12 @@ func (a *Access) Healthy() (*health.Info, error) { if err != nil { healthy = false - moreInfo[infoKey] = messages.CertificateInfoFailed.String() + moreInfo[ca] = string(messages.CertStatusFailed) continue } - moreInfo[infoKey] = messages.CertificateInfo{ - Status: messages.CertStatusOk, - Signing: true, - Profiles: def.Profiles, - ValidUntil: cert.NotAfter.UTC(), - }.String() + moreInfo[ca] = string(messages.CertStatusOk) } return &health.Info{ @@ -141,54 +177,25 @@ func NewAccess(logger *logrus.Logger, options ...ConfigOption) (*Access, error) return access, nil } -func (c *caFile) buildCertificatePath(caDirectory string) string { - fileName := c.sc.CertificateFileName(c.label) - - if caDirectory == "" { - return fileName - } - - return path.Join(caDirectory, fileName) -} - -func (c *caFile) loadCertificate(caDirectory string) (*x509.Certificate, error) { - certFile := c.buildCertificatePath(caDirectory) - - certFileInfo, err := os.Stat(certFile) - if err != nil { - if errors.Is(err, syscall.ENOENT) { - return nil, nil - } - - return nil, fmt.Errorf("could not get info for %s: %w", certFile, err) - } - - if !certFileInfo.Mode().IsRegular() { - return nil, fmt.Errorf("certificate file %s is not a regular file", certFile) - } +func (a *Access) GetCAInfo(name string) (*cainfo.Result, error) { + sc := a.GetSignerConfig() - certData, err := os.ReadFile(certFile) - if err != nil { - return nil, fmt.Errorf("could not read %s: %w", certFile, err) - } + caFile := &caFile{sc: sc, label: name} - certificate, err := x509.ParseCertificate(certData) + def, err := sc.GetCADefinition(name) if err != nil { - return nil, fmt.Errorf("could not parse certificate from %s: %w", certFile, err) + return nil, fmt.Errorf("certificate %s unknown: %w", name, err) } - return certificate, nil -} - -func (c *caFile) storeCertificate(caDirectory string, certificate []byte) error { - certFile := c.buildCertificatePath(caDirectory) - - err := os.WriteFile(certFile, certificate, 0o600) + certificate, err := caFile.loadCertificate(a.caDirectory) if err != nil { - return fmt.Errorf("could not write certificate file %s: %w", certFile, err) + return nil, fmt.Errorf("certificate %s not available: %w", name, err) } - return nil + return &cainfo.Result{ + Certificate: certificate.Raw, + Profiles: def.Profiles, + }, nil } func (a *Access) GetRootCACertificate(label string) (*x509.Certificate, error) { diff --git a/pkg/messages/messages.go b/pkg/messages/messages.go index 3257367..f208c9e 100644 --- a/pkg/messages/messages.go +++ b/pkg/messages/messages.go @@ -22,7 +22,6 @@ package messages import ( "crypto/x509" - "encoding/json" "encoding/pem" "fmt" "math/big" @@ -40,13 +39,21 @@ type CommandCode int8 const ( CmdUndef CommandCode = iota CmdHealth + CmdCAInfo CmdFetchCRL + CmdSignCertificate + CmdSignOpenPGP + CmdRevokeCertificate ) var commandNames = map[CommandCode]string{ - CmdUndef: "UNDEFINED", - CmdHealth: "HEALTH", - CmdFetchCRL: "FETCH CRL", + CmdUndef: "UNDEFINED", + CmdHealth: "HEALTH", + CmdFetchCRL: "FETCH CRL", + CmdCAInfo: "CA INFO", + CmdSignCertificate: "SIG CERT", + CmdSignOpenPGP: "SIG OPENPGP", + CmdRevokeCertificate: "REV CERT", } func (c CommandCode) String() string { @@ -63,14 +70,22 @@ const ( RespError ResponseCode = -1 RespUndef ResponseCode = iota RespHealth + RespCAInfo RespFetchCRL + RespSignCertificate + RespSignOpenPGP + RespRevokeCertificate ) var responseNames = map[ResponseCode]string{ - RespError: "ERROR", - RespUndef: "UNDEFINED", - RespHealth: "HEALTH", - RespFetchCRL: "FETCH CRL", + RespError: "ERROR", + RespUndef: "UNDEFINED", + RespHealth: "HEALTH", + RespCAInfo: "CA INFO", + RespFetchCRL: "FETCH CRL", + RespSignCertificate: "SIG CERT", + RespSignOpenPGP: "SIG OPENPGP", + RespRevokeCertificate: "REV CERT", } func (c ResponseCode) String() string { @@ -111,13 +126,20 @@ func BuildResponseAnnounce(code ResponseCode, commandID string) *ResponseAnnounc return &ResponseAnnounce{Code: code, ID: commandID, Created: time.Now().UTC()} } -type HealthCommand struct { -} +type HealthCommand struct{} func (h *HealthCommand) String() string { return "" } +type CAInfoCommand struct { + Name string `msgpack:"name"` +} + +func (r *CAInfoCommand) String() string { + return fmt.Sprintf("name=%s", r.Name) +} + type FetchCRLCommand struct { IssuerID string `msgpack:"issuer_id"` LastKnownID []byte `msgpack:"last_known_id"` @@ -226,8 +248,8 @@ func ParseUsage(u string) (ProfileUsage, error) { } type CAProfile struct { - Name string `json:"name"` - UseFor ProfileUsage `json:"use-for"` + Name string `msgpack:"name"` + UseFor ProfileUsage `msgpack:"use-for"` } func (p CAProfile) String() string { @@ -241,33 +263,15 @@ const ( CertStatusFailed CertificateStatus = "failed" ) -type CertificateInfo struct { - Status CertificateStatus `json:"status"` - Signing bool `json:"signing"` - Profiles []CAProfile `json:"profiles,omitempty"` - ValidUntil time.Time `json:"valid-until"` -} - -func (i CertificateInfo) String() string { - marshal, _ := json.Marshal(i) - - return string(marshal) -} - -var CertificateInfoFailed = CertificateInfo{ - Status: CertStatusFailed, - Signing: false, +type CAInfoResponse struct { + Name string `msgpack:"name"` + Certificate []byte `msgpack:"certificate"` + Signing bool `msgpack:"signing"` + Profiles []CAProfile `msgpack:"profiles,omitempty"` } -func ParseCertificateInfo(info string) (*CertificateInfo, error) { - certInfo := CertificateInfo{} - - err := json.Unmarshal([]byte(info), &certInfo) - if err != nil { - return nil, fmt.Errorf("could not parse certificate information: %w", err) - } - - return &certInfo, nil +func (i CAInfoResponse) String() string { + return fmt.Sprintf("certificate name=%s, signing=%t, profiles=[%s]", i.Name, i.Signing, i.Profiles) } type HealthInfo struct { diff --git a/pkg/messages/messages_test.go b/pkg/messages/messages_test.go index be5a195..b795e07 100644 --- a/pkg/messages/messages_test.go +++ b/pkg/messages/messages_test.go @@ -18,6 +18,7 @@ limitations under the License. package messages import ( + "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" @@ -328,81 +329,38 @@ func TestCAProfile_String(t *testing.T) { } } -func TestCertificateInfo_String(t *testing.T) { - infoInstances := []struct { - Name string - info CertificateInfo - }{ - {"failed", CertificateInfoFailed}, - {"ok", - CertificateInfo{ - Status: CertStatusOk, - Signing: true, - Profiles: []CAProfile{{ - Name: "test", - UseFor: UsageServer, - }}, - ValidUntil: time.Now().UTC(), - }, - }, - } +func TestCAInfoCommand_String(t *testing.T) { + c := CAInfoCommand{Name: "test"} - for _, i := range infoInstances { - t.Run(i.Name, func(t *testing.T) { - str := i.info.String() + str := c.String() - assert.NotEmpty(t, str) - assert.Contains(t, str, fmt.Sprintf("%t", i.info.Signing)) - assert.True(t, strings.HasPrefix(str, "{")) - assert.True(t, strings.HasSuffix(str, "}")) - assert.Contains(t, str, "status") - assert.Contains(t, str, "signing") - - if len(i.info.Profiles) == 0 { - assert.NotContains(t, str, "profiles") - } else { - assert.Contains(t, str, "profiles") - } - - if i.info.ValidUntil.IsZero() { - assert.Contains(t, str, `"valid-until":"0001-01-01T00:00:00Z"`) - } else { - assert.Contains(t, str, "valid-until") - } - }) - } + assert.NotEmpty(t, str) + assert.Contains(t, str, "test") + assert.Contains(t, str, "name") } -func TestParseCertificateInfo(t *testing.T) { - brokenVariants := []struct{ Name, Value string }{ - {"no json", "no json for you"}, - {"invalid-status", `{"status":"foo"`}, - {"invalid-date", `{"status":"failed","valid-until":"foo"`}, +func TestCAInfoResponse_String(t *testing.T) { + _, certBytes := createTestCertificate(t) + + info := CAInfoResponse{ + Name: "testca", + Signing: true, + Profiles: []CAProfile{{ + Name: "test", + UseFor: UsageServer, + }}, + Certificate: certBytes, } - for _, v := range brokenVariants { - t.Run(v.Name, func(t *testing.T) { - i, err := ParseCertificateInfo(v.Value) - - assert.Error(t, err) - assert.Nil(t, i) - }) - } - - okVariants := []struct{ Name, Value string }{ - {"minimal", `{"status":"failed"}`}, - {"signing", `{"status":"ok","signing":true}`}, - {"with-date", `{"status":"ok","signing":false,"valid-until":"2022-12-31T23:59:59+01:00"}`}, - } + str := info.String() - for _, v := range okVariants { - t.Run(v.Name, func(t *testing.T) { - i, err := ParseCertificateInfo(v.Value) + assert.NotEmpty(t, str) + assert.Contains(t, str, fmt.Sprintf("signing=%t", info.Signing)) + assert.Contains(t, str, "certificate name") + assert.Contains(t, str, "profiles") - assert.NoError(t, err) - require.NotNil(t, i) - assert.NotEmpty(t, i.Status) - }) + if len(info.Profiles) == 0 { + assert.Contains(t, str, "[]") } } @@ -545,27 +503,7 @@ func TestFetchCRLResponse_String(t *testing.T) { }) t.Run("good-crl", func(t *testing.T) { - keyPair, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - - require.NoError(t, err) - - certTemplate := &x509.Certificate{ - BasicConstraintsValid: true, - IsCA: true, - Issuer: pkix.Name{Country: []string{"un"}, Organization: []string{"Acme Ltd."}, CommonName: "foo CA"}, - KeyUsage: x509.KeyUsageCRLSign | x509.KeyUsageCertSign, - MaxPathLen: 0, - MaxPathLenZero: false, - NotAfter: time.Now().AddDate(5, 0, 0), - NotBefore: time.Now(), - SerialNumber: big.NewInt(1), - SignatureAlgorithm: x509.ECDSAWithSHA256, - Subject: pkix.Name{Country: []string{"un"}, Organization: []string{"Acme Ltd."}, CommonName: "foo CA"}, - } - - certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, keyPair.Public(), keyPair) - - require.NoError(t, err) + keyPair, certBytes := createTestCertificate(t) cert, _ := x509.ParseCertificate(certBytes) @@ -597,6 +535,34 @@ func TestFetchCRLResponse_String(t *testing.T) { }) } +func createTestCertificate(t *testing.T) (crypto.Signer, []byte) { + t.Helper() + + keyPair, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + + require.NoError(t, err) + + certTemplate := &x509.Certificate{ + BasicConstraintsValid: true, + IsCA: true, + Issuer: pkix.Name{Country: []string{"un"}, Organization: []string{"Acme Ltd."}, CommonName: "foo CA"}, + KeyUsage: x509.KeyUsageCRLSign | x509.KeyUsageCertSign, + MaxPathLen: 0, + MaxPathLenZero: false, + NotAfter: time.Now().AddDate(5, 0, 0), + NotBefore: time.Now(), + SerialNumber: big.NewInt(1), + SignatureAlgorithm: x509.ECDSAWithSHA256, + Subject: pkix.Name{Country: []string{"un"}, Organization: []string{"Acme Ltd."}, CommonName: "foo CA"}, + } + + certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, keyPair.Public(), keyPair) + + require.NoError(t, err) + + return keyPair, certBytes +} + func TestErrorResponse_String(t *testing.T) { r := &ErrorResponse{Message: "kaput"} diff --git a/pkg/messages/resolver.msgpackgen.go b/pkg/messages/resolver.msgpackgen.go index 1be380e..068705c 100644 --- a/pkg/messages/resolver.msgpackgen.go +++ b/pkg/messages/resolver.msgpackgen.go @@ -56,6 +56,36 @@ func ___encodeAsArray(i interface{}) ([]byte, error) { return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthCommand", size, offset) } return b, err + case CAInfoCommand: + encoder := enc.NewEncoder() + size, err := ___calcArraySizeCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeArrayCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "CAInfoCommand", size, offset) + } + return b, err + case *CAInfoCommand: + encoder := enc.NewEncoder() + size, err := ___calcArraySizeCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeArrayCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "CAInfoCommand", size, offset) + } + return b, err case FetchCRLCommand: encoder := enc.NewEncoder() size, err := ___calcArraySizeFetchCRLCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) @@ -243,6 +273,36 @@ func ___encodeAsMap(i interface{}) ([]byte, error) { return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthCommand", size, offset) } return b, err + case CAInfoCommand: + encoder := enc.NewEncoder() + size, err := ___calcMapSizeCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeMapCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "CAInfoCommand", size, offset) + } + return b, err + case *CAInfoCommand: + encoder := enc.NewEncoder() + size, err := ___calcMapSizeCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder) + if err != nil { + return nil, err + } + encoder.MakeBytes(size) + b, offset, err := ___encodeMapCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0) + if err != nil { + return nil, err + } + if size != offset { + return nil, fmt.Errorf("%s size / offset different %d : %d", "CAInfoCommand", size, offset) + } + return b, err case FetchCRLCommand: encoder := enc.NewEncoder() size, err := ___calcMapSizeFetchCRLCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder) @@ -423,6 +483,20 @@ func ___decodeAsArray(data []byte, i interface{}) (bool, error) { return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) } return true, err + case *CAInfoCommand: + decoder := dec.NewDecoder(data) + offset, err := ___decodeArrayCAInfoCommand_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 **CAInfoCommand: + decoder := dec.NewDecoder(data) + offset, err := ___decodeArrayCAInfoCommand_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 *FetchCRLCommand: decoder := dec.NewDecoder(data) offset, err := ___decodeArrayFetchCRLCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) @@ -514,6 +588,20 @@ func ___decodeAsMap(data []byte, i interface{}) (bool, error) { return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len()) } return true, err + case *CAInfoCommand: + decoder := dec.NewDecoder(data) + offset, err := ___decodeMapCAInfoCommand_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 **CAInfoCommand: + decoder := dec.NewDecoder(data) + offset, err := ___decodeMapCAInfoCommand_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 *FetchCRLCommand: decoder := dec.NewDecoder(data) offset, err := ___decodeMapFetchCRLCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, decoder, 0) @@ -663,6 +751,107 @@ func ___decodeMapHealthCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f8 return offset, err } +// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.CAInfoCommand +func ___calcArraySizeCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v CAInfoCommand, encoder *enc.Encoder) (int, error) { + size := 0 + size += encoder.CalcStructHeaderFix(1) + size += encoder.CalcString(v.Name) + return size, nil +} + +// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.CAInfoCommand +func ___calcMapSizeCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v CAInfoCommand, encoder *enc.Encoder) (int, error) { + size := 0 + size += encoder.CalcStructHeaderFix(1) + size += encoder.CalcStringFix(4) + size += encoder.CalcString(v.Name) + return size, nil +} + +// encode from git.cacert.org/cacert-gosigner/pkg/messages.CAInfoCommand +func ___encodeArrayCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v CAInfoCommand, encoder *enc.Encoder, offset int) ([]byte, int, error) { + var err error + offset = encoder.WriteStructHeaderFixAsArray(1, offset) + offset = encoder.WriteString(v.Name, offset) + return encoder.EncodedBytes(), offset, err +} + +// encode from git.cacert.org/cacert-gosigner/pkg/messages.CAInfoCommand +func ___encodeMapCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v CAInfoCommand, encoder *enc.Encoder, offset int) ([]byte, int, error) { + var err error + offset = encoder.WriteStructHeaderFixAsMap(1, offset) + offset = encoder.WriteStringFix("name", 4, offset) + offset = encoder.WriteString(v.Name, offset) + return encoder.EncodedBytes(), offset, err +} + +// decode to git.cacert.org/cacert-gosigner/pkg/messages.CAInfoCommand +func ___decodeArrayCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *CAInfoCommand, decoder *dec.Decoder, offset int) (int, error) { + offset, err := decoder.CheckStructHeader(1, offset) + if err != nil { + return 0, err + } + { + var vv string + vv, offset, err = decoder.AsString(offset) + if err != nil { + return 0, err + } + v.Name = vv + } + return offset, err +} + +// decode to git.cacert.org/cacert-gosigner/pkg/messages.CAInfoCommand +func ___decodeMapCAInfoCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *CAInfoCommand, decoder *dec.Decoder, offset int) (int, error) { + keys := [][]byte{ + {uint8(0x6e), uint8(0x61), uint8(0x6d), uint8(0x65)}, // name + } + offset, err := decoder.CheckStructHeader(1, offset) + if err != nil { + return 0, err + } + count := 0 + for count < 1 { + 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.Name = vv + } + 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.FetchCRLCommand func ___calcArraySizeFetchCRLCommand_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v FetchCRLCommand, encoder *enc.Encoder) (int, error) { size := 0