diff options
Diffstat (limited to 'descriptor')
| -rw-r--r-- | descriptor/descriptor.go | 62 | ||||
| -rw-r--r-- | descriptor/descriptor_test.go | 96 | ||||
| -rw-r--r-- | descriptor/stfe.json | 18 | 
3 files changed, 176 insertions, 0 deletions
| diff --git a/descriptor/descriptor.go b/descriptor/descriptor.go new file mode 100644 index 0000000..267a401 --- /dev/null +++ b/descriptor/descriptor.go @@ -0,0 +1,62 @@ +package descriptor + +import ( +	"bytes" +	"fmt" + +	"crypto" +	"crypto/tls" +	"crypto/x509" +	"encoding/base64" +	"encoding/json" +	"io/ioutil" +) + +// 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 FindLog(ops []Operator, logId []byte) (*Log, error) { +	for _, op := range ops { +		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)) +} + +// LoadOperators loads a list of json-encoded log operators from a given path +func LoadOperators(path string) ([]Operator, error) { +	blob, err := ioutil.ReadFile(path) +	if err != nil { +		return nil, fmt.Errorf("failed reading log operators: %v", err) +	} +	var ops []Operator +	if err := json.Unmarshal(blob, &ops); err != nil { +		return nil, fmt.Errorf("failed decoding log operators: %v", err) +	} +	return ops, nil +} + +func (l *Log) Key() crypto.PublicKey { +	k, err := x509.ParsePKIXPublicKey(l.PublicKey) +	if err != nil { +		panic("TODO: make a new function and parse public key there") +	} +	return k +} diff --git a/descriptor/descriptor_test.go b/descriptor/descriptor_test.go new file mode 100644 index 0000000..d01fc66 --- /dev/null +++ b/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 { +		ops       []Operator +		logId     []byte +		wantError bool +	}{ +		{makeOperatorList(), deb64("B9oCJk4XIOMXba8dBM5yUj+NLtqTE6xHwbvR9dYkHPM="), false}, +		{makeOperatorList(), []byte{0, 1, 2, 3}, true}, +	} { +		_, err := FindLog(table.ops, 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/descriptor/stfe.json b/descriptor/stfe.json new file mode 100644 index 0000000..d987c47 --- /dev/null +++ b/descriptor/stfe.json @@ -0,0 +1,18 @@ +[ +    { +        "name": "Test operator", +        "email": "test@example.com", +        "logs": [ +            { +                "max_chain": 3, +                "id": "B9oCJk4XIOMXba8dBM5yUj+NLtqTE6xHwbvR9dYkHPM=", +                "signature_schemes": [ +                    2055 +                ], +                "base_url": "localhost:6965/st/v1", +                "signature_scheme": 2055, +                "public_key": "MCowBQYDK2VwAyEAqM4b/SHOCRId9xgiCPn8D8r6+Nrk9JTZZqW6vj7TGa0=" +            } +        ] +    } +] | 
