penguin/homekey-go

homekey-go

internal/provision/auth_test.go

raw ยท 3021 bytes

package provision

import (
	"bytes"
	"encoding/hex"
	"testing"
)

func TestAuthenticationPersistenceAndRevocation(t *testing.T) {
	s, dir, iid := paired(t)
	if _, e := s.Handle(readerAdd()); e != nil {
		t.Fatal(e)
	}
	if _, e := s.Handle(endpointAdd(iid)); e != nil {
		t.Fatal(e)
	}
	c := s.AuthenticationCredentials()
	var eid, pub string
	for id, ep := range c.Issuers[iid].Endpoints {
		eid = id
		pub = ep.PublicKey
	}
	key := bytes.Repeat([]byte{7}, 32)
	if e := s.SaveAuthenticatedKey(c, iid, eid, pub, key); e != nil {
		t.Fatal(e)
	}
	restored, e := Open(dir)
	if e != nil {
		t.Fatal(e)
	}
	if restored.AuthenticationCredentials().Issuers[iid].Endpoints[eid].PersistentKey == "" {
		t.Fatal("persistent key lost")
	}
	// Mutating a snapshot must never modify the live credential store.
	delete(c.Issuers, iid)
	c = s.AuthenticationCredentials()
	calls := 0
	if e := s.WithAuthorization(c, iid, eid, pub, func() error { calls++; return nil }); e != nil {
		t.Fatal(e)
	}
	if e := s.Delete("controller.pairing"); e != nil {
		t.Fatal(e)
	}
	if e := s.SaveAuthenticatedKey(c, iid, eid, pub, key); e == nil {
		t.Fatal("revoked credential persisted")
	}
	if e := s.WithAuthorization(c, iid, eid, pub, func() error { calls++; return nil }); e == nil {
		t.Fatal("revoked credential unlocked")
	}
	if calls != 1 {
		t.Fatal("callback ran after revocation")
	}
}
func TestAuthenticationRejectsReaderChangeAndInactive(t *testing.T) {
	for _, mode := range []string{"reader", "inactive"} {
		t.Run(mode, func(t *testing.T) {
			s, _, iid := paired(t)
			s.Handle(readerAdd())
			s.Handle(endpointAdd(iid))
			c := s.AuthenticationCredentials()
			var eid, pub string
			for id, ep := range c.Issuers[iid].Endpoints {
				eid = id
				pub = ep.PublicKey
			}
			e := s.update(func(d *Data) error {
				if mode == "reader" {
					d.HomeKey.ReaderIdentifier = "0908070605040302"
				} else {
					i := d.HomeKey.Issuers[iid]
					ep := i.Endpoints[eid]
					ep.KeyState = 0
					i.Endpoints[eid] = ep
					d.HomeKey.Issuers[iid] = i
				}
				return nil
			})
			if e != nil {
				t.Fatal(e)
			}
			if e = s.WithAuthorization(c, iid, eid, pub, func() error { t.Fatal("unauthorized callback"); return nil }); e == nil {
				t.Fatal("changed credentials accepted")
			}
		})
	}
}

func TestReaderGroupIdentifier(t *testing.T) {
	s, _, _ := paired(t)
	if s.ReaderGroupIdentifier() != nil {
		t.Fatal("unprovisioned reader has ECP group")
	}
	if _, err := s.Handle(readerAdd()); err != nil {
		t.Fatal(err)
	}
	// Independent SHA256("key-identifier" || scalar=1) vector.
	want := mustHex("539a3f91ed603fef")
	group := s.ReaderGroupIdentifier()
	if !bytes.Equal(group, want) {
		t.Fatalf("wrong group: %s", hex.EncodeToString(group))
	}
	group[0] ^= 1
	if !bytes.Equal(s.ReaderGroupIdentifier(), want) {
		t.Fatal("group snapshot aliases store")
	}
	if _, err := s.Handle(request(3, 6, TLV(4, want))); err != nil {
		t.Fatal(err)
	}
	if s.ReaderGroupIdentifier() != nil {
		t.Fatal("removed reader still has ECP group")
	}
}