diff options
Diffstat (limited to 'namespace')
| -rw-r--r-- | namespace/namespace.go | 150 | ||||
| -rw-r--r-- | namespace/namespace_test.go | 218 | ||||
| -rw-r--r-- | namespace/testdata/data.go | 21 | 
3 files changed, 0 insertions, 389 deletions
| diff --git a/namespace/namespace.go b/namespace/namespace.go deleted file mode 100644 index f5c56cf..0000000 --- a/namespace/namespace.go +++ /dev/null @@ -1,150 +0,0 @@ -// Package namespace provides namespace functionality.  A namespace refers to a -// particular verification key and signing algorithm that can be serialized with -// TLS 1.2 notation, see RFC 5246 (ยง4).  Only Ed25519 is supported at this time. -// -// For example, this is how a serialized Ed25519 namespace looks like: -// -// 0    2    3                  35 (byte index) -// +----+-----------------------+ -// | 1  + 32 + Verification key + -// +----+-----------------------+ -package namespace - -import ( -	"fmt" - -	"crypto/ed25519" - -	"github.com/google/certificate-transparency-go/tls" -) - -// NamespaceFormat defines a particular namespace type that is versioend -type NamespaceFormat tls.Enum - -const ( -	NamespaceFormatReserved  NamespaceFormat = 0 -	NamespaceFormatEd25519V1 NamespaceFormat = 1 -) - -// Namespace references a versioned namespace based on a given format specifier -type Namespace struct { -	Format             NamespaceFormat     `tls:"maxval:65535"` -	NamespaceEd25519V1 *NamespaceEd25519V1 `tls:"selector:Format,val:1"` -} - -// NamespaceEd25519V1 uses an Ed25519 verification key as namespace.  Encoding, -// signing, and verification operations are defined by RFC 8032. -type NamespaceEd25519V1 struct { -	Namespace []byte `tls:"minlen:32,maxlen:32"` -} - -// String returns a human-readable representation of a namespace. -func (n Namespace) String() string { -	switch n.Format { -	case NamespaceFormatEd25519V1: -		return fmt.Sprintf("%x", n.NamespaceEd25519V1.Namespace) -	default: -		return "reserved" -	} -} - -// NewNamespaceEd25519V1 returns an new Ed25519V1 namespace based on a -// verification key. -func NewNamespaceEd25519V1(vk []byte) (*Namespace, error) { -	if len(vk) != 32 { -		return nil, fmt.Errorf("invalid verification key: must be 32 bytes") -	} -	return &Namespace{ -		Format: NamespaceFormatEd25519V1, -		NamespaceEd25519V1: &NamespaceEd25519V1{ -			Namespace: vk, -		}, -	}, nil -} - -// Verify checks that signature is valid over message for this namespace -func (ns *Namespace) Verify(message, signature []byte) error { -	switch ns.Format { -	case NamespaceFormatEd25519V1: -		if !ed25519.Verify(ed25519.PublicKey(ns.NamespaceEd25519V1.Namespace), message, signature) { -			return fmt.Errorf("ed25519 signature verification failed") -		} -	default: -		return fmt.Errorf("namespace not supported: %v", ns.Format) -	} -	return nil -} - -func (ns *Namespace) Marshal() ([]byte, error) { -	serialized, err := tls.Marshal(*ns) -	if err != nil { -		return nil, fmt.Errorf("marshaled failed for namespace(%v): %v", ns.Format, err) -	} -	return serialized, err -} - -func (ns *Namespace) Unmarshal(serialized []byte) error { -	extra, err := tls.Unmarshal(serialized, ns) -	if err != nil { -		return fmt.Errorf("unmarshal failed for namespace: %v", err) -	} else if len(extra) > 0 { -		return fmt.Errorf("unmarshal found extra data for namespace(%v): %v", ns.Format, err) -	} -	return nil -} - -// NamespacePool is a pool of namespaces that contain complete verification keys -type NamespacePool struct { -	pool map[string]*Namespace -	list []*Namespace -	// If we need to update this structure without a restart => add mutex. -} - -// NewNameSpacePool creates a new namespace pool from a list of namespaces.  An -// error is returned if there are duplicate namespaces or namespaces without a -// complete verification key.  The latter is determined by namespaceWithKey(). -func NewNamespacePool(namespaces []*Namespace) (*NamespacePool, error) { -	np := &NamespacePool{ -		pool: make(map[string]*Namespace), -		list: make([]*Namespace, 0), -	} -	for _, namespace := range namespaces { -		if !namespaceWithKey(namespace.Format) { -			return nil, fmt.Errorf("need verification key in namespace pool: %v", namespace.Format) -		} -		if _, ok := np.pool[namespace.String()]; ok { -			return nil, fmt.Errorf("duplicate namespace: %v", namespace.String()) -		} -		np.pool[namespace.String()] = namespace -		np.list = append(np.list, namespace) -	} -	return np, nil -} - -// Find checks if namespace is a member of the namespace pool. -func (np *NamespacePool) Find(namespace *Namespace) (*Namespace, bool) { -	if _, ok := np.pool[namespace.String()]; !ok { -		return nil, false -	} -	// If the passed namespace is a key fingerprint the actual key needs to be -	// attached before returning.  Not applicable for Ed25519.  Docdoc later. -	return namespace, true -} - -// List returns a copied list of namespaces that is used by this pool. -func (np *NamespacePool) List() []*Namespace { -	namespaces := make([]*Namespace, len(np.list)) -	copy(namespaces, np.list) -	return namespaces -} - -// namespaceWithKey returns true if a namespace format contains a complete -// verification key.  I.e., some formats might have a key fingerprint instead. -func namespaceWithKey(format NamespaceFormat) bool { -	switch format { -	case NamespaceFormatEd25519V1: -		return true -	default: -		return false -	} -} diff --git a/namespace/namespace_test.go b/namespace/namespace_test.go deleted file mode 100644 index 10c0bf0..0000000 --- a/namespace/namespace_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package namespace - -import ( -	"bytes" -	"testing" - -	"crypto/ed25519" - -	"github.com/system-transparency/stfe/namespace/testdata" -) - -func TestNewNamespaceEd25519V1(t *testing.T) { -	for _, table := range []struct { -		description string -		vk          []byte -		wantErr     bool -	}{ -		{ -			description: "invalid", -			vk:          append(testdata.Ed25519Vk, 0x00), -			wantErr:     true, -		}, -		{ -			description: "valid", -			vk:          testdata.Ed25519Vk, -		}, -	} { -		n, err := NewNamespaceEd25519V1(table.vk) -		if got, want := err != nil, table.wantErr; got != want { -			t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) -		} -		if err != nil { -			continue -		} -		if got, want := n.Format, NamespaceFormatEd25519V1; got != want { -			t.Errorf("got namespace format %v but wanted %v in test %q", got, want, table.description) -			continue -		} -		if got, want := n.NamespaceEd25519V1.Namespace, table.vk; !bytes.Equal(got, want) { -			t.Errorf("got namespace %X but wanted %X in test %q", got, want, table.description) -		} -	} -} - -func TestVerify(t *testing.T) { -	testMsg := []byte("msg") -	for _, table := range []struct { -		description string -		namespace   *Namespace -		msg, sig    []byte -		wantErr     bool -	}{ -		{ -			description: "invalid: unsupported namespace", -			namespace:   &Namespace{Format: NamespaceFormatReserved}, -			msg:         testMsg, -			sig:         []byte("sig"), -			wantErr:     true, -		}, -		{ -			description: "invalid: bad ed25519 verification key", -			namespace:   mustNewNamespaceEd25519V1(t, testdata.Ed25519Sk[:32]), -			msg:         testMsg, -			sig:         ed25519.Sign(ed25519.PrivateKey(testdata.Ed25519Sk), testMsg), -			wantErr:     true, -		}, -		{ -			description: "invalid: ed25519 signature is not over message", -			namespace:   mustNewNamespaceEd25519V1(t, testdata.Ed25519Vk), -			msg:         append(testMsg, 0x00), -			sig:         ed25519.Sign(ed25519.PrivateKey(testdata.Ed25519Sk), testMsg), -			wantErr:     true, -		}, -		{ -			description: "valid: ed25519", -			namespace:   mustNewNamespaceEd25519V1(t, testdata.Ed25519Vk), -			msg:         testMsg, -			sig:         ed25519.Sign(ed25519.PrivateKey(testdata.Ed25519Sk), testMsg), -		}, -	} { -		err := table.namespace.Verify(table.msg, table.sig) -		if got, want := err != nil, table.wantErr; got != want { -			t.Errorf("got error=%v but wanted %v in test %q: %v", got, want, table.description, err) -		} -	} -} - -func TestMarshal(t *testing.T) { -	for _, table := range []struct { -		description string -		namespace   *Namespace -		wantErr     bool -		wantBytes   []byte -	}{ -		{ -			description: "invalid ed25519: namespace size too small", -			namespace: &Namespace{ -				Format: NamespaceFormatEd25519V1, -				NamespaceEd25519V1: &NamespaceEd25519V1{ -					Namespace: testdata.Ed25519Vk[:len(testdata.Ed25519Vk)-1], -				}, -			}, -			wantErr: true, -		}, -		{ -			description: "invalid ed25519: namespace size too large", -			namespace: &Namespace{ -				Format: NamespaceFormatEd25519V1, -				NamespaceEd25519V1: &NamespaceEd25519V1{ -					Namespace: append(testdata.Ed25519Vk, 0x00), -				}, -			}, -			wantErr: true, -		}, -		{ -			description: "valid: ed25519", -			namespace:   mustNewNamespaceEd25519V1(t, testdata.Ed25519Vk), -			// TODO: wantBytes -		}, -	} { -		_, err := table.namespace.Marshal() -		if got, want := err != nil, table.wantErr; got != want { -			t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) -		} -		if err != nil { -			continue -		} -		// TODO: add check that we got the bytes we wanted also -	} -} - -func TestUnmarshal(t *testing.T) { -	// TODO -} - -func TestNewNamespacePool(t *testing.T) { -	ns1, _ := NewNamespaceEd25519V1(testdata.Ed25519Vk) -	ns2, _ := NewNamespaceEd25519V1(make([]byte, 32)) -	nsr := &Namespace{Format: NamespaceFormatReserved} -	for _, table := range []struct { -		description string -		namespaces  []*Namespace -		wantErr     bool -	}{ -		{ -			description: "invalid: duplicate namespace", -			namespaces:  []*Namespace{ns1, ns1, ns2}, -			wantErr:     true, -		}, -		{ -			description: "invalid: namespace without key", -			namespaces:  []*Namespace{ns1, nsr, ns2}, -			wantErr:     true, -		}, -		{ -			description: "valid: empty", -			namespaces:  []*Namespace{}, -		}, -		{ -			description: "valid: one namespace", -			namespaces:  []*Namespace{ns1}, -		}, -		{ -			description: "valid: two namespaces", -			namespaces:  []*Namespace{ns1, ns2}, -		}, -	} { -		_, err := NewNamespacePool(table.namespaces) -		if got, want := err != nil, table.wantErr; got != want { -			t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) -		} -	} -} - -func TestFind(t *testing.T) { -	ns1 := mustNewNamespaceEd25519V1(t, testdata.Ed25519Vk) -	ns2 := mustNewNamespaceEd25519V1(t, make([]byte, 32)) -	pool, _ := NewNamespacePool(nil) -	_, got := pool.Find(ns1) -	if want := false; got != want { -		t.Errorf("got %v but wanted %v in test %q", got, want, "empty pool") -	} - -	pool, _ = NewNamespacePool([]*Namespace{ns1}) -	_, got = pool.Find(ns1) -	if want := true; got != want { -		t.Errorf("got %v but wanted %v in test %q", got, want, "non-empty pool: looking for member") -	} -	_, got = pool.Find(ns2) -	if want := false; got != want { -		t.Errorf("got %v but wanted %v in test %q", got, want, "non-empty pool: looking for non-member") -	} -} - -func TestList(t *testing.T) { -	ns1 := mustNewNamespaceEd25519V1(t, testdata.Ed25519Vk) -	ns2 := mustNewNamespaceEd25519V1(t, make([]byte, 32)) -	namespaces := []*Namespace{ns1, ns2} -	pool, _ := NewNamespacePool(namespaces) -	l1 := pool.List() -	if got, want := len(l1), len(namespaces); got != want { -		t.Errorf("got len %v but wanted %v", got, want) -	} - -	l1[0] = ns2 -	l2 := pool.List() -	if bytes.Equal(l1[0].NamespaceEd25519V1.Namespace, l2[0].NamespaceEd25519V1.Namespace) { -		t.Errorf("returned list is not a copy") -	} -} - -func mustNewNamespaceEd25519V1(t *testing.T, vk []byte) *Namespace { -	namespace, err := NewNamespaceEd25519V1(vk) -	if err != nil { -		t.Fatalf("must make ed25519 namespace: %v", err) -	} -	return namespace -} diff --git a/namespace/testdata/data.go b/namespace/testdata/data.go deleted file mode 100644 index 5f3f4df..0000000 --- a/namespace/testdata/data.go +++ /dev/null @@ -1,21 +0,0 @@ -package testdata - -import ( -	"encoding/base64" -) - -var ( -	Ed25519Vk = mustDecodeB64("HOQFUkKNWpjYAhNKTyWCzahlI7RDtf5123kHD2LACj0=") -	Ed25519Sk = mustDecodeB64("Zaajc50Xt1tNpTj6WYkljzcVjLXL2CcQcHFT/xZqYEcc5AVSQo1amNgCE0pPJYLNqGUjtEO1/nXbeQcPYsAKPQ==") - -	Ed25519Vk2 = mustDecodeB64("LqrWb9JwQUTk/SwTNDdMH8aRmy3mbmhwEepO5WSgb+A=") -	Ed25519Sk2 = mustDecodeB64("fDkSq4cWvG72yMhUyHVcZ72QKerZ66msgyVqDvfufZQuqtZv0nBBROT9LBM0N0wfxpGbLeZuaHAR6k7lZKBv4A==") - -	Ed25519Vk3 = mustDecodeB64("Icd1U1oY0z+5iAwgCQZyGI+pycGs6GI2rQO8gAzT7Y0=") -	Ed25519Sk3 = mustDecodeB64("Q6uNL7VKv9flaBIXBXy/NyhNOicLYKKmfuJ6tLReMvQhx3VTWhjTP7mIDCAJBnIYj6nJwazoYjatA7yADNPtjQ==") -) - -func mustDecodeB64(s string) []byte { -	b, _ := base64.StdEncoding.DecodeString(s) -	return b -} | 
