From 801afaa9147c4f70fc00fde1993f6ce0c91bd450 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Mon, 2 Nov 2020 17:04:13 +0100 Subject: added stfe server descriptor A collection of immutable log parameters, see documentation. --- server/descriptor/descriptor.go | 40 +++++++++++++++ server/descriptor/descriptor_test.go | 96 ++++++++++++++++++++++++++++++++++++ server/descriptor/stfe.json | 18 +++++++ 3 files changed, 154 insertions(+) create mode 100644 server/descriptor/descriptor.go create mode 100644 server/descriptor/descriptor_test.go create mode 100644 server/descriptor/stfe.json (limited to 'server/descriptor') diff --git a/server/descriptor/descriptor.go b/server/descriptor/descriptor.go new file mode 100644 index 0000000..ba90289 --- /dev/null +++ b/server/descriptor/descriptor.go @@ -0,0 +1,40 @@ +package descriptor + +import ( + "bytes" + "fmt" + + "crypto/tls" + "encoding/base64" +) + +const ( + // Location is an url to a json-encoded list of stfe log operators + Location = "https://github.com/system-transparency/stfe/tree/main/server/descriptor/stfe.json" +) + +// Operator is an stfe log operator that runs zero or more logs +type Operator struct { + Name string `json:"name"` + Email string `json:"email"` + Logs []*Log `json:"logs"` +} + +// Log is a collection of immutable stfe log parameters +type Log struct { + Id []byte `json:"id"` // H(PublicKey) + PublicKey []byte `json:"public_key"` // DER-encoded SubjectPublicKeyInfo + Scheme tls.SignatureScheme `json:"signature_scheme"` // Signature schemes used by the log (RFC 8446, §4.2.3) + Schemes []tls.SignatureScheme `json:"signature_schemes"` // Signature schemes that submitters can use (RFC 8446, §4.2.3) + MaxChain uint8 `json:"max_chain"` // maximum certificate chain length + BaseUrl string `json:"base_url"` // E.g., example.com/st/v1 +} + +func (op *Operator) FindLog(logId []byte) (*Log, error) { + for _, log := range op.Logs { + if bytes.Equal(logId, log.Id) { + return log, nil + } + } + return nil, fmt.Errorf("no such log: %s", base64.StdEncoding.EncodeToString(logId)) +} diff --git a/server/descriptor/descriptor_test.go b/server/descriptor/descriptor_test.go new file mode 100644 index 0000000..e461f88 --- /dev/null +++ b/server/descriptor/descriptor_test.go @@ -0,0 +1,96 @@ +package descriptor + +import ( + "fmt" + "testing" + + "crypto/sha256" + "crypto/tls" + "encoding/base64" + "encoding/json" +) + +const ( + operatorListJson = `[{"name":"Test operator","email":"test@example.com","logs":[{"id":"B9oCJk4XIOMXba8dBM5yUj+NLtqTE6xHwbvR9dYkHPM=","public_key":"MCowBQYDK2VwAyEAqM4b/SHOCRId9xgiCPn8D8r6+Nrk9JTZZqW6vj7TGa0=","signature_scheme":2055,"signature_schemes":[2055],"max_chain":3,"base_url":"example.com/st/v1"}]}]` +) + +func TestMarshal(t *testing.T) { + for _, table := range []struct { + in []Operator + want string + }{ + {makeOperatorList(), operatorListJson}, + } { + b, err := json.Marshal(table.in) + if err != nil { + t.Errorf("operator list marshaling failed: %v", err) + } + if string(b) != table.want { + t.Errorf("\nwant %s\n got %s", table.want, string(b)) + } + } + +} + +func TestUnmarshal(t *testing.T) { + for _, table := range []struct { + in []byte + want error + }{ + {[]byte(operatorListJson), nil}, + } { + var op []Operator + if err := json.Unmarshal(table.in, &op); err != table.want { + t.Errorf("wanted err=%v, got %v", table.want, err) + } + } +} + +func TestFindLog(t *testing.T) { + for _, table := range []struct { + op Operator + logId []byte + wantError bool + }{ + {makeOperatorList()[0], deb64("B9oCJk4XIOMXba8dBM5yUj+NLtqTE6xHwbvR9dYkHPM="), false}, + {makeOperatorList()[0], []byte{0, 1, 2, 3}, true}, + } { + _, err := table.op.FindLog(table.logId) + if (err != nil) != table.wantError { + t.Errorf("wanted log not found for id: %v", table.logId) + } + } +} + +func makeOperatorList() []Operator { + pub := deb64("MCowBQYDK2VwAyEAqM4b/SHOCRId9xgiCPn8D8r6+Nrk9JTZZqW6vj7TGa0=") + h := sha256.New() + h.Write(pub) + id := h.Sum(nil) + return []Operator{ + Operator{ + Name: "Test operator", + Email: "test@example.com", + Logs: []*Log{ + &Log{ + Id: id, + PublicKey: pub, + Scheme: tls.Ed25519, + Schemes: []tls.SignatureScheme{ + tls.Ed25519, + }, + MaxChain: 3, + BaseUrl: "example.com/st/v1", + }, + }, + }, + } +} + +func deb64(s string) []byte { + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(fmt.Sprintf("failed decoding base64: %v", err)) + } + return b +} diff --git a/server/descriptor/stfe.json b/server/descriptor/stfe.json new file mode 100644 index 0000000..69e84a0 --- /dev/null +++ b/server/descriptor/stfe.json @@ -0,0 +1,18 @@ +[ + { + "name": "Test operator", + "email": "test@example.com", + "logs": [ + { + "max_chain": 3, + "log_id": "B9oCJk4XIOMXba8dBM5yUj+NLtqTE6xHwbvR9dYkHPM=", + "signature_schemes": [ + 2055 + ], + "base_url": "example.com/st/v1", + "signature_scheme": 2055, + "public_key": "MCowBQYDK2VwAyEAqM4b/SHOCRId9xgiCPn8D8r6+Nrk9JTZZqW6vj7TGa0=" + } + ] + } +] -- cgit v1.2.3