Implement serial link and protocol handling infrastructure
This commit adds basic serial link and protocol support. None of the commands from the docs/design.md document is implemented yet. The following new packages have been added: - seriallink containing the serial link handler including COBS decoding and encoding - protocol containing the protocol handler including msgpack unmarshalling and marshaling - health containing a rudimentary health check implementation - messages containing command and response types and generated msgpack marshaling code A client simulation command has been added in cmd/clientsim. README.md got instructions how to run the client simulator. The docs/config.sample.yaml contains a new section for the serial connection parameters.
This commit is contained in:
parent
c2b987fd31
commit
3107ad8abb
16 changed files with 1058 additions and 7 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -2,6 +2,9 @@
|
|||
*.pem
|
||||
*.pub
|
||||
.idea/
|
||||
/clientsim
|
||||
/signer
|
||||
/testPty
|
||||
ca-hierarchy.json
|
||||
config.yaml
|
||||
dist/
|
21
README.md
21
README.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Setup HSM keys and certificates
|
||||
|
||||
```
|
||||
```shell
|
||||
sudo apt install softhsm2
|
||||
umask 077
|
||||
mkdir -p ~/.config/softhsm2/tokens
|
||||
|
@ -17,7 +17,24 @@ go run ./cmd/signer -setup
|
|||
|
||||
## Run the signer
|
||||
|
||||
```
|
||||
```shell
|
||||
export PKCS11_PIN_LOCALHSM=123456
|
||||
go run ./cmd/signer
|
||||
```
|
||||
|
||||
## Run the client simulator with socat
|
||||
|
||||
You may run the client simulator that sends commands via `stdout` and reads responses on `stdin` via `socat` to
|
||||
simulate traffic on an emulated serial device:
|
||||
|
||||
```shell
|
||||
sudo apt install socat
|
||||
```
|
||||
|
||||
```shell
|
||||
go build ./cmd/clientsim
|
||||
socat -d -d -v pty,rawer,link=$(pwd)/testPty EXEC:./clientsim,pty,rawer
|
||||
```
|
||||
|
||||
You will need to configure `$(pwd)/testPty` as `serial`/`device` in your `config.yaml` to let the signer command find
|
||||
the emulated serial device.
|
144
cmd/clientsim/main.go
Normal file
144
cmd/clientsim/main.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// client simulator
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/justincpresley/go-cobs"
|
||||
"github.com/shamaton/msgpackgen/msgpack"
|
||||
|
||||
"git.cacert.org/cacert-gosigner/pkg/messages"
|
||||
)
|
||||
|
||||
const cobsDelimiter = 0x00
|
||||
|
||||
var cobsConfig = cobs.Config{SpecialByte: cobsDelimiter, Delimiter: true, EndingSave: true}
|
||||
|
||||
func main() {
|
||||
const (
|
||||
bufferSize = 1024 * 1024
|
||||
readInterval = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
errors := make(chan error)
|
||||
|
||||
errorLog := log.New(os.Stderr, "", log.LstdFlags)
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
done := make(chan struct{})
|
||||
frame := make(chan []byte)
|
||||
|
||||
go func(done chan struct{}) {
|
||||
buf := make([]byte, bufferSize)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
wg.Done()
|
||||
|
||||
return
|
||||
|
||||
default:
|
||||
count, err := os.Stdin.Read(buf)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
|
||||
wg.Done()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
time.Sleep(readInterval)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
data := buf[:count]
|
||||
|
||||
err = cobs.Verify(data, cobsConfig)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
|
||||
wg.Done()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
frame <- cobs.Decode(data, cobsConfig)
|
||||
}
|
||||
}
|
||||
}(done)
|
||||
|
||||
err := writeTestCommands(frame, errorLog)
|
||||
if err != nil {
|
||||
errorLog.Printf("could not write test commands")
|
||||
}
|
||||
|
||||
err = <-errors
|
||||
if err != nil {
|
||||
errorLog.Printf("error: %v", err)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func writeTestCommands(responses chan []byte, errorLog *log.Logger) error {
|
||||
messages.RegisterGeneratedResolver()
|
||||
|
||||
commands := []messages.Command{
|
||||
{
|
||||
Code: messages.CmdHealth,
|
||||
TimeStamp: time.Now().UTC(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, command := range commands {
|
||||
commandBytes, err := msgpack.Marshal(command)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not marshal command bytes: %w", err)
|
||||
}
|
||||
|
||||
_, err = os.Stdout.Write(cobs.Encode(commandBytes, cobsConfig))
|
||||
if err != nil {
|
||||
return fmt.Errorf("write failed: %w", err)
|
||||
}
|
||||
|
||||
responseBytes := <-responses
|
||||
|
||||
var response messages.Response
|
||||
|
||||
err = msgpack.Unmarshal(responseBytes, &response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not unmarshal msgpack data: %w", err)
|
||||
}
|
||||
|
||||
errorLog.Printf("received response: %+v", response)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -23,7 +23,10 @@ import (
|
|||
"os"
|
||||
|
||||
"git.cacert.org/cacert-gosigner/pkg/config"
|
||||
"git.cacert.org/cacert-gosigner/pkg/health"
|
||||
"git.cacert.org/cacert-gosigner/pkg/hsm"
|
||||
"git.cacert.org/cacert-gosigner/pkg/protocol"
|
||||
"git.cacert.org/cacert-gosigner/pkg/seriallink"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -97,5 +100,23 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
healthHandler := health.New(version)
|
||||
|
||||
proto, err := protocol.New(infoLog, errorLog, protocol.RegisterHealthHandler(healthHandler))
|
||||
if err != nil {
|
||||
errorLog.Fatalf("could not setup protocol handler: %v", err)
|
||||
}
|
||||
|
||||
serialHandler, err := seriallink.New(caConfig.GetSerial(), proto)
|
||||
if err != nil {
|
||||
errorLog.Fatalf("could not setup serial link handler: %v", err)
|
||||
}
|
||||
|
||||
defer func() { _ = serialHandler.Close() }()
|
||||
|
||||
if err = serialHandler.Run(); err != nil {
|
||||
errorLog.Fatalf("error in serial handler: %v", err)
|
||||
}
|
||||
|
||||
infoLog.Print("setup complete, starting signer operation")
|
||||
}
|
||||
|
|
|
@ -24,6 +24,12 @@ Settings:
|
|||
ocsp: "http://ocsp.cacert.org/"
|
||||
crl: "http://crl.cacert.org/%s.crl"
|
||||
issuer: "http://www.cacert.org/certs/%s.crt"
|
||||
# Settings for the serial link
|
||||
# baud and timeout-millis are optional
|
||||
serial:
|
||||
device: "/dev/ttyUSB0"
|
||||
baud: 115200
|
||||
timeout-millis: 5000
|
||||
|
||||
# KeyStorage defines PKCS#11 tokens, a token named 'default' must be present
|
||||
KeyStorage:
|
||||
|
|
8
go.mod
8
go.mod
|
@ -4,9 +4,12 @@ go 1.17
|
|||
|
||||
require (
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/justincpresley/go-cobs v1.2.0
|
||||
github.com/shamaton/msgpackgen v0.3.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -14,6 +17,7 @@ require (
|
|||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/shamaton/msgpack/v2 v2.1.0 // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
|
||||
)
|
||||
|
|
17
go.sum
17
go.sum
|
@ -1,8 +1,11 @@
|
|||
github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E=
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE=
|
||||
github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA=
|
||||
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/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=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
|
@ -11,10 +14,18 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/shamaton/msgpack/v2 v2.1.0 h1:9jJ2eGZw2Wa9KExPX3KaDDckVjgr4zhXGFCfWagUWqg=
|
||||
github.com/shamaton/msgpack/v2 v2.1.0/go.mod h1:aTUEmh31ziGX1Ml7wMPLVY0f4vT3CRsCvZRoSCs+VGg=
|
||||
github.com/shamaton/msgpackgen v0.3.0 h1:q6o7prOEJFdF9BAPgkOtfzJbs55pQi7g44RUnEVUxtM=
|
||||
github.com/shamaton/msgpackgen v0.3.0/go.mod h1:fd99fDDuxuTiWzkHC59uEGzrt/WDu+ltGZTbEWwVXIc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
|
||||
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
|
@ -24,5 +35,5 @@ golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuX
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -31,6 +31,12 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Serial struct {
|
||||
Device string
|
||||
Baud int
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
type Settings struct {
|
||||
Organization *pkix.Name
|
||||
ValidityYears struct {
|
||||
|
@ -39,6 +45,7 @@ type Settings struct {
|
|||
URLPatterns struct {
|
||||
Ocsp, CRL, Issuer string
|
||||
}
|
||||
Serial *Serial
|
||||
}
|
||||
|
||||
type SettingsError struct {
|
||||
|
@ -67,6 +74,11 @@ func (s *Settings) UnmarshalYAML(n *yaml.Node) error {
|
|||
CRL string `yaml:"crl"`
|
||||
Issuer string `yaml:"issuer"`
|
||||
} `yaml:"url-patterns"`
|
||||
Serial struct {
|
||||
Device string `yaml:"device"`
|
||||
Baud int `yaml:"baud"`
|
||||
TimeoutMillis int `yaml:"timeout-millis"`
|
||||
} `yaml:"serial"`
|
||||
}{}
|
||||
|
||||
err := n.Decode(&data)
|
||||
|
@ -111,6 +123,18 @@ func (s *Settings) UnmarshalYAML(n *yaml.Node) error {
|
|||
return SettingsError{"url-pattern 'issuer' must contain one '%s' placeholder"}
|
||||
}
|
||||
|
||||
if data.Serial.Device == "" {
|
||||
return SettingsError{"you must specify a serial 'device'"}
|
||||
}
|
||||
|
||||
if data.Serial.Baud == 0 {
|
||||
data.Serial.Baud = 115200
|
||||
}
|
||||
|
||||
if data.Serial.TimeoutMillis == 0 {
|
||||
data.Serial.TimeoutMillis = 5000
|
||||
}
|
||||
|
||||
s.Organization = &pkix.Name{}
|
||||
s.Organization.Organization = data.Organization.Organization
|
||||
s.Organization.Country = data.Organization.Country
|
||||
|
@ -125,6 +149,12 @@ func (s *Settings) UnmarshalYAML(n *yaml.Node) error {
|
|||
s.URLPatterns.CRL = data.URLPatterns.CRL
|
||||
s.URLPatterns.Issuer = data.URLPatterns.Issuer
|
||||
|
||||
s.Serial = &Serial{
|
||||
Device: data.Serial.Device,
|
||||
Baud: data.Serial.Baud,
|
||||
Timeout: time.Duration(data.Serial.TimeoutMillis) * time.Millisecond,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -287,6 +317,10 @@ func (c *SignerConfig) GetKeyStorage(label string) (*KeyStorage, error) {
|
|||
return keyStorage, nil
|
||||
}
|
||||
|
||||
func (c *SignerConfig) GetSerial() *Serial {
|
||||
return c.global.Serial
|
||||
}
|
||||
|
||||
// LoadConfiguration reads YAML configuration from the given reader as a SignerConfig structure
|
||||
func LoadConfiguration(r io.Reader) (*SignerConfig, error) {
|
||||
config := struct {
|
||||
|
|
|
@ -421,6 +421,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/
|
||||
crl: http://crl.example.org/%s
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
KeyStorage:
|
||||
default:
|
||||
type: softhsm
|
||||
|
@ -476,6 +478,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/
|
||||
crl: http://crl.example.org/%s.crl
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
CAs:
|
||||
root:
|
||||
common-name: "Root CA"
|
||||
|
@ -497,6 +501,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/
|
||||
crl: http://crl.example.org/%s.crl
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
KeyStorage:
|
||||
default:
|
||||
label: default
|
||||
|
@ -533,6 +539,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/
|
||||
crl: http://crl.example.org/%s.crl
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
KeyStorage:
|
||||
default:
|
||||
type: softhsm
|
||||
|
@ -656,6 +664,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/%s
|
||||
crl: http://crl.example.org/%s.crl
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
KeyStorage:
|
||||
default:
|
||||
type: softhsm
|
||||
|
|
27
pkg/health/health.go
Normal file
27
pkg/health/health.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
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 health implements Health checks
|
||||
package health
|
||||
|
||||
type Handler struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
func New(version string) *Handler {
|
||||
return &Handler{Version: version}
|
||||
}
|
|
@ -183,6 +183,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/
|
||||
crl: http://crl.example.org/%s.crl
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
CAs:
|
||||
root:
|
||||
common-name: "Acme CAs root"
|
||||
|
|
|
@ -157,6 +157,8 @@ Settings:
|
|||
ocsp: http://ocsp.example.org/
|
||||
crl: http://crl.example.org/%s.crl
|
||||
issuer: http://%s.cas.example.org/
|
||||
serial:
|
||||
device: /dev/ttyUSB0
|
||||
CAs:
|
||||
root:
|
||||
common-name: "Acme CAs root"
|
||||
|
|
68
pkg/messages/messages.go
Normal file
68
pkg/messages/messages.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
//go:generate go run github.com/shamaton/msgpackgen
|
||||
|
||||
// Package messages contains structure definitions for protocol messages
|
||||
package messages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CommandCode int
|
||||
|
||||
const (
|
||||
CmdHealth CommandCode = iota
|
||||
)
|
||||
|
||||
func (c CommandCode) String() string {
|
||||
switch c {
|
||||
case CmdHealth:
|
||||
return "HEALTH"
|
||||
default:
|
||||
return fmt.Sprintf("unknown (%d)", int(c))
|
||||
}
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
Code CommandCode `msgpack:"code"`
|
||||
TimeStamp time.Time `msgpack:"created"`
|
||||
Payload interface{} `msgpack:"payload"` // optional payload
|
||||
}
|
||||
|
||||
type ResponseCode int
|
||||
|
||||
const (
|
||||
RspError ResponseCode = -1
|
||||
RspHealth ResponseCode = iota
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Code ResponseCode `msgpack:"code"`
|
||||
TimeStamp time.Time `msgpack:"created"`
|
||||
Payload interface{} `msgpack:"payload"`
|
||||
}
|
||||
|
||||
type HealthResponse struct {
|
||||
Version string `msgpack:"version"`
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Message string `msgpack:"message"`
|
||||
}
|
439
pkg/messages/resolver.msgpackgen.go
Normal file
439
pkg/messages/resolver.msgpackgen.go
Normal file
|
@ -0,0 +1,439 @@
|
|||
// Code generated by msgpackgen. DO NOT EDIT.
|
||||
|
||||
package messages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
msgpack "github.com/shamaton/msgpackgen/msgpack"
|
||||
dec "github.com/shamaton/msgpackgen/msgpack/dec"
|
||||
enc "github.com/shamaton/msgpackgen/msgpack/enc"
|
||||
)
|
||||
|
||||
// RegisterGeneratedResolver registers generated resolver.
|
||||
func RegisterGeneratedResolver() {
|
||||
msgpack.SetResolver(___encodeAsMap, ___encodeAsArray, ___decodeAsMap, ___decodeAsArray)
|
||||
}
|
||||
|
||||
// encode
|
||||
func ___encode(i interface{}) ([]byte, error) {
|
||||
if msgpack.StructAsArray() {
|
||||
return ___encodeAsArray(i)
|
||||
} else {
|
||||
return ___encodeAsMap(i)
|
||||
}
|
||||
}
|
||||
|
||||
// encodeAsArray
|
||||
func ___encodeAsArray(i interface{}) ([]byte, error) {
|
||||
switch v := i.(type) {
|
||||
case HealthResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcArraySizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
case *HealthResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcArraySizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
case ErrorResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "ErrorResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
case *ErrorResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "ErrorResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// encodeAsMap
|
||||
func ___encodeAsMap(i interface{}) ([]byte, error) {
|
||||
switch v := i.(type) {
|
||||
case HealthResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcMapSizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
case *HealthResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcMapSizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "HealthResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
case ErrorResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcMapSizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "ErrorResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
case *ErrorResponse:
|
||||
encoder := enc.NewEncoder()
|
||||
size, err := ___calcMapSizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoder.MakeBytes(size)
|
||||
b, offset, err := ___encodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(*v, encoder, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if size != offset {
|
||||
return nil, fmt.Errorf("%s size / offset different %d : %d", "ErrorResponse", size, offset)
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// decode
|
||||
func ___decode(data []byte, i interface{}) (bool, error) {
|
||||
if msgpack.StructAsArray() {
|
||||
return ___decodeAsArray(data, i)
|
||||
} else {
|
||||
return ___decodeAsMap(data, i)
|
||||
}
|
||||
}
|
||||
|
||||
// decodeAsArray
|
||||
func ___decodeAsArray(data []byte, i interface{}) (bool, error) {
|
||||
switch v := i.(type) {
|
||||
case *HealthResponse:
|
||||
decoder := dec.NewDecoder(data)
|
||||
offset, err := ___decodeArrayHealthResponse_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 **HealthResponse:
|
||||
decoder := dec.NewDecoder(data)
|
||||
offset, err := ___decodeArrayHealthResponse_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)
|
||||
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)
|
||||
if err == nil && offset != decoder.Len() {
|
||||
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// decodeAsMap
|
||||
func ___decodeAsMap(data []byte, i interface{}) (bool, error) {
|
||||
switch v := i.(type) {
|
||||
case *HealthResponse:
|
||||
decoder := dec.NewDecoder(data)
|
||||
offset, err := ___decodeMapHealthResponse_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 **HealthResponse:
|
||||
decoder := dec.NewDecoder(data)
|
||||
offset, err := ___decodeMapHealthResponse_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)
|
||||
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)
|
||||
if err == nil && offset != decoder.Len() {
|
||||
return true, fmt.Errorf("read length is different [%d] [%d] ", offset, decoder.Len())
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse
|
||||
func ___calcArraySizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder) (int, error) {
|
||||
size := 0
|
||||
size += encoder.CalcStructHeaderFix(1)
|
||||
size += encoder.CalcString(v.Version)
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse
|
||||
func ___calcMapSizeHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder) (int, error) {
|
||||
size := 0
|
||||
size += encoder.CalcStructHeaderFix(1)
|
||||
size += encoder.CalcStringFix(7)
|
||||
size += encoder.CalcString(v.Version)
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse
|
||||
func ___encodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) {
|
||||
var err error
|
||||
offset = encoder.WriteStructHeaderFixAsArray(1, offset)
|
||||
offset = encoder.WriteString(v.Version, offset)
|
||||
return encoder.EncodedBytes(), offset, err
|
||||
}
|
||||
|
||||
// encode from git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse
|
||||
func ___encodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v HealthResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) {
|
||||
var err error
|
||||
offset = encoder.WriteStructHeaderFixAsMap(1, offset)
|
||||
offset = encoder.WriteStringFix("version", 7, offset)
|
||||
offset = encoder.WriteString(v.Version, offset)
|
||||
return encoder.EncodedBytes(), offset, err
|
||||
}
|
||||
|
||||
// decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse
|
||||
func ___decodeArrayHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthResponse, 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.Version = vv
|
||||
}
|
||||
return offset, err
|
||||
}
|
||||
|
||||
// decode to git.cacert.org/cacert-gosigner/pkg/messages.HealthResponse
|
||||
func ___decodeMapHealthResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *HealthResponse, decoder *dec.Decoder, offset int) (int, error) {
|
||||
keys := [][]byte{
|
||||
{uint8(0x76), uint8(0x65), uint8(0x72), uint8(0x73), uint8(0x69), uint8(0x6f), uint8(0x6e)}, // version
|
||||
}
|
||||
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.Version = 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.ErrorResponse
|
||||
func ___calcArraySizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder) (int, error) {
|
||||
size := 0
|
||||
size += encoder.CalcStructHeaderFix(1)
|
||||
size += encoder.CalcString(v.Message)
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// calculate size from git.cacert.org/cacert-gosigner/pkg/messages.ErrorResponse
|
||||
func ___calcMapSizeErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder) (int, error) {
|
||||
size := 0
|
||||
size += encoder.CalcStructHeaderFix(1)
|
||||
size += encoder.CalcStringFix(7)
|
||||
size += encoder.CalcString(v.Message)
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// encode from git.cacert.org/cacert-gosigner/pkg/messages.ErrorResponse
|
||||
func ___encodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) {
|
||||
var err error
|
||||
offset = encoder.WriteStructHeaderFixAsArray(1, offset)
|
||||
offset = encoder.WriteString(v.Message, offset)
|
||||
return encoder.EncodedBytes(), offset, err
|
||||
}
|
||||
|
||||
// encode from git.cacert.org/cacert-gosigner/pkg/messages.ErrorResponse
|
||||
func ___encodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v ErrorResponse, encoder *enc.Encoder, offset int) ([]byte, int, error) {
|
||||
var err error
|
||||
offset = encoder.WriteStructHeaderFixAsMap(1, offset)
|
||||
offset = encoder.WriteStringFix("message", 7, offset)
|
||||
offset = encoder.WriteString(v.Message, offset)
|
||||
return encoder.EncodedBytes(), offset, err
|
||||
}
|
||||
|
||||
// decode to git.cacert.org/cacert-gosigner/pkg/messages.ErrorResponse
|
||||
func ___decodeArrayErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *ErrorResponse, 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.Message = vv
|
||||
}
|
||||
return offset, err
|
||||
}
|
||||
|
||||
// decode to git.cacert.org/cacert-gosigner/pkg/messages.ErrorResponse
|
||||
func ___decodeMapErrorResponse_e587a81c7cb163b35488bdef0f58c292f99f4bd65a81377f81e5b18c3d86855d(v *ErrorResponse, decoder *dec.Decoder, offset int) (int, error) {
|
||||
keys := [][]byte{
|
||||
{uint8(0x6d), uint8(0x65), uint8(0x73), uint8(0x73), uint8(0x61), uint8(0x67), uint8(0x65)}, // message
|
||||
}
|
||||
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.Message = vv
|
||||
}
|
||||
count++
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown key[%s] found", string(dataKey))
|
||||
}
|
||||
}
|
||||
return offset, err
|
||||
}
|
129
pkg/protocol/protocol.go
Normal file
129
pkg/protocol/protocol.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
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 handles the protocol message marshaling and unmarshalling.
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/shamaton/msgpackgen/msgpack"
|
||||
|
||||
"git.cacert.org/cacert-gosigner/pkg/health"
|
||||
"git.cacert.org/cacert-gosigner/pkg/messages"
|
||||
)
|
||||
|
||||
// Handler is responsible for parsing incoming frames and calling commands
|
||||
type Handler interface {
|
||||
HandleFrame([]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type MsgPackHandler struct {
|
||||
infoLog, errorLog *log.Logger
|
||||
healthHandler *health.Handler
|
||||
}
|
||||
|
||||
func (m *MsgPackHandler) HandleFrame(frame []byte) ([]byte, error) {
|
||||
var command messages.Command
|
||||
|
||||
err := msgpack.Unmarshal(frame, &command)
|
||||
if err != nil {
|
||||
m.errorLog.Printf("unmarshal failed: %v", err)
|
||||
|
||||
errorResponse, innerErr := buildErrorResponse("do not understand")
|
||||
if innerErr != nil {
|
||||
return nil, innerErr
|
||||
}
|
||||
|
||||
return errorResponse, nil
|
||||
}
|
||||
|
||||
m.infoLog.Printf("Received %s command sent at %s", command.Code, command.TimeStamp)
|
||||
|
||||
response, err := m.handleCommand(&command)
|
||||
if err != nil {
|
||||
m.errorLog.Printf("command failed: %v", err)
|
||||
|
||||
errorResponse, innerErr := buildErrorResponse("command failed")
|
||||
if innerErr != nil {
|
||||
return nil, innerErr
|
||||
}
|
||||
|
||||
return errorResponse, nil
|
||||
}
|
||||
|
||||
responseData, err := msgpack.Marshal(response)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not marshal response: %w", err)
|
||||
}
|
||||
|
||||
return responseData, nil
|
||||
}
|
||||
|
||||
func (m *MsgPackHandler) handleCommand(command *messages.Command) (*messages.Response, error) {
|
||||
var (
|
||||
payload interface{}
|
||||
responseCode messages.ResponseCode
|
||||
)
|
||||
|
||||
switch command.Code {
|
||||
case messages.CmdHealth:
|
||||
responseCode, payload = messages.RspHealth, messages.HealthResponse{Version: m.healthHandler.Version}
|
||||
default:
|
||||
return nil, fmt.Errorf("unhandled command %s", command)
|
||||
}
|
||||
|
||||
return &messages.Response{TimeStamp: time.Now().UTC(), Code: responseCode, Payload: payload}, nil
|
||||
}
|
||||
|
||||
func buildErrorResponse(errMsg string) ([]byte, error) {
|
||||
marshal, err := msgpack.Marshal(&messages.Response{
|
||||
Code: messages.RspError,
|
||||
TimeStamp: time.Now().UTC(),
|
||||
Payload: messages.ErrorResponse{Message: errMsg},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not marshal error response: %w", err)
|
||||
}
|
||||
|
||||
return marshal, nil
|
||||
}
|
||||
|
||||
func New(infoLog *log.Logger, errorLog *log.Logger, handlers ...RegisterHandler) (Handler, error) {
|
||||
messages.RegisterGeneratedResolver()
|
||||
|
||||
h := &MsgPackHandler{
|
||||
infoLog: infoLog,
|
||||
errorLog: errorLog,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
134
pkg/seriallink/seriallink.go
Normal file
134
pkg/seriallink/seriallink.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
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 seriallink provides a handler for the serial connection of the signer machine.
|
||||
package seriallink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/justincpresley/go-cobs"
|
||||
"github.com/tarm/serial"
|
||||
|
||||
"git.cacert.org/cacert-gosigner/pkg/config"
|
||||
"git.cacert.org/cacert-gosigner/pkg/protocol"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
protocolHandler protocol.Handler
|
||||
config *serial.Config
|
||||
port *serial.Port
|
||||
}
|
||||
|
||||
func (h *Handler) setupConnection() error {
|
||||
s, err := serial.OpenPort(h.config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open serial port: %w", err)
|
||||
}
|
||||
|
||||
h.port = s
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) Close() error {
|
||||
err := h.port.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not close serial port: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const cobsDelimiter = 0x00
|
||||
|
||||
func (h *Handler) Run() error {
|
||||
const (
|
||||
bufferSize = 1024 * 1024
|
||||
readInterval = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
errors := make(chan error)
|
||||
|
||||
cobsConfig := cobs.Config{SpecialByte: cobsDelimiter, Delimiter: true, EndingSave: true}
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, bufferSize)
|
||||
|
||||
for {
|
||||
count, err := h.port.Read(buf)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
time.Sleep(readInterval)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
err = cobs.Verify(buf[:count], cobsConfig)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// perform COBS decoding
|
||||
decoded := cobs.Decode(buf[:count], cobsConfig)
|
||||
|
||||
msg, err := h.protocolHandler.HandleFrame(decoded)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// perform COBS encoding
|
||||
encoded := cobs.Encode(msg, cobsConfig)
|
||||
|
||||
_, err = h.port.Write(encoded)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err := <-errors
|
||||
if err != nil {
|
||||
return fmt.Errorf("error from handler loop: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func New(cfg *config.Serial, protocolHandler protocol.Handler) (*Handler, error) {
|
||||
h := &Handler{protocolHandler: protocolHandler}
|
||||
h.config = &serial.Config{Name: cfg.Device, Baud: cfg.Baud, ReadTimeout: cfg.Timeout}
|
||||
|
||||
err := h.setupConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
Loading…
Reference in a new issue