mirror of
https://github.com/cloudflare/redoctober.git
synced 2025-12-23 06:15:45 +00:00
+ Add a lock to the keycache.
+ Ensure that all instantiations of keycaches use New, rather
than the old keycache.Cache{make()} construct. This no longer
works with the lock in place.
+ Update travis to run the race detector on a few specific packages
that should help identify this type of problem in the future.
433 lines
9.3 KiB
Go
433 lines
9.3 KiB
Go
// keycache_test.go: tests for keycache.go
|
|
//
|
|
// Copyright (c) 2013 CloudFlare, Inc.
|
|
package keycache
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cloudflare/redoctober/passvault"
|
|
"github.com/cloudflare/redoctober/symcrypt"
|
|
)
|
|
|
|
func TestUsesFlush(t *testing.T) {
|
|
// Initialize passvault with one dummy user.
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
// Initialize keycache and delegate the user's key to it.
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(pr, "user", "weakpassword", nil, nil, 2, "", "1h")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
removed := cache.Refresh()
|
|
if removed != 0 {
|
|
t.Fatalf("No active users should have been removed")
|
|
}
|
|
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys")
|
|
}
|
|
|
|
// Generate a random symmetric key, encrypt a blank block with it, and encrypt
|
|
// the key itself with the user's public key.
|
|
dummy := make([]byte, 16)
|
|
key, err := symcrypt.MakeRandom(16)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
encKey, err := symcrypt.EncryptCBC(dummy, dummy, key)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pubEncryptedKey, err := pr.EncryptKey(key)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
key2, err := cache.DecryptKey(encKey, "user", "anybody", []string{}, pubEncryptedKey)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
if bytes.Equal(key, key2) {
|
|
t.Fatal("cache.DecryptKey didnt decrypt the right key!")
|
|
}
|
|
|
|
// Second decryption allowed.
|
|
_, err = cache.DecryptKey(encKey, "user", "anybody else", []string{}, pubEncryptedKey)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
if len(cache.UserKeys) != 0 {
|
|
t.Fatalf("Error in number of live keys %v", cache.UserKeys)
|
|
}
|
|
}
|
|
|
|
func TestTimeFlush(t *testing.T) {
|
|
// Initialize passvault and keycache. Delegate a key for 1s, wait a
|
|
// second and then make sure that it's gone.
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(pr, "user", "weakpassword", nil, nil, 10, "", "10s")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys")
|
|
}
|
|
|
|
time.Sleep(11 * time.Second)
|
|
|
|
dummy := make([]byte, 16)
|
|
pubEncryptedKey, err := pr.EncryptKey(dummy)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
_, err = cache.DecryptKey(dummy, "user", "anybody", []string{}, pubEncryptedKey)
|
|
if err == nil {
|
|
t.Fatalf("Error in pruning expired key")
|
|
}
|
|
}
|
|
|
|
func TestGoodLabel(t *testing.T) {
|
|
// Initialize passvault and keycache. Delegate a key with the tag "red" and
|
|
// verify that decryption with the tag "red" is allowed.
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(pr, "user", "weakpassword", nil, []string{"red"}, 1, "", "1h")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys")
|
|
}
|
|
|
|
dummy := make([]byte, 16)
|
|
pubEncryptedKey, err := pr.EncryptKey(dummy)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
_, err = cache.DecryptKey(dummy, "user", "anybody", []string{"red"}, pubEncryptedKey)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
if len(cache.UserKeys) != 0 {
|
|
t.Fatalf("Error in number of live keys %v", cache.UserKeys)
|
|
}
|
|
}
|
|
|
|
func TestBadLabel(t *testing.T) {
|
|
// Initialize passvault and keycache. Delegate a key with the tag "red" and
|
|
// verify that decryption with the tag "blue" is disallowed.
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(pr, "user", "weakpassword", nil, []string{"red"}, 1, "", "1h")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys")
|
|
}
|
|
|
|
dummy := make([]byte, 16)
|
|
pubEncryptedKey, err := pr.EncryptKey(dummy)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
_, err = cache.DecryptKey(dummy, "user", "anybody", []string{"blue"}, pubEncryptedKey)
|
|
if err == nil {
|
|
t.Fatalf("Decryption of labeled key allowed without permission.")
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys %v", cache.UserKeys)
|
|
}
|
|
}
|
|
|
|
func TestGoodUser(t *testing.T) {
|
|
// Initialize passvault and keycache. Delegate a key with tag and user
|
|
// restrictions and verify that permissible decryption is allowed.
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(
|
|
pr, "user", "weakpassword",
|
|
[]string{"ci", "buildeng", "user"},
|
|
[]string{"red", "blue"},
|
|
1, "", "1h",
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys")
|
|
}
|
|
|
|
dummy := make([]byte, 16)
|
|
pubEncryptedKey, err := pr.EncryptKey(dummy)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
_, err = cache.DecryptKey(dummy, "user", "ci", []string{"red"}, pubEncryptedKey)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 0 {
|
|
t.Fatalf("Error in number of live keys %v", cache.UserKeys)
|
|
}
|
|
}
|
|
|
|
func TestBadUser(t *testing.T) {
|
|
// Initialize passvault and keycache. Delegate a key with tag and user
|
|
// restrictions and verify that illegal decryption is disallowed.
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(
|
|
pr, "user", "weakpassword",
|
|
[]string{"ci", "buildeng", "user"},
|
|
[]string{"red", "blue"},
|
|
1, "", "1h",
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys")
|
|
}
|
|
|
|
dummy := make([]byte, 16)
|
|
pubEncryptedKey, err := pr.EncryptKey(dummy)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
_, err = cache.DecryptKey(dummy, "user", "anybody", []string{"blue"}, pubEncryptedKey)
|
|
if err == nil {
|
|
t.Fatalf("Decryption of labeled key allowed without permission.")
|
|
}
|
|
|
|
cache.Refresh()
|
|
if len(cache.UserKeys) != 1 {
|
|
t.Fatalf("Error in number of live keys %v", cache.UserKeys)
|
|
}
|
|
}
|
|
|
|
func TestRefresh(t *testing.T) {
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
pr, err := records.AddNewRecord("user", "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
err = cache.AddKeyFromRecord(
|
|
pr, "user", "weakpassword",
|
|
[]string{"ci", "buildeng", "user"},
|
|
[]string{"red", "blue"},
|
|
1, "", "10s",
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
removed := cache.Refresh()
|
|
if removed != 0 {
|
|
t.Fatalf("Refresh should not have removed any active users.")
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
|
|
|
removed = cache.Refresh()
|
|
if removed != 1 {
|
|
t.Fatalf("Refresh should have removed an active user, removed %d", removed)
|
|
}
|
|
|
|
if len(cache.GetSummary()) != 0 {
|
|
t.Fatalf("There should be no active users in the cache, but there are %d", len(cache.GetSummary()))
|
|
}
|
|
}
|
|
|
|
func cmpEntry(c, d ActiveUser) bool {
|
|
if c.Uses != d.Uses {
|
|
return false
|
|
}
|
|
|
|
if len(c.Labels) != len(d.Labels) {
|
|
return false
|
|
}
|
|
|
|
for i := range c.Labels {
|
|
if c.Labels[i] != d.Labels[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if len(c.Users) != len(d.Users) {
|
|
return false
|
|
}
|
|
|
|
for i := range c.Users {
|
|
if c.Users[i] != d.Users[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if c.Expiry != d.Expiry {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func cmpCache(a, b Cache) bool {
|
|
if len(a.UserKeys) != len(b.UserKeys) {
|
|
return false
|
|
}
|
|
|
|
for aIndex, aUser := range a.UserKeys {
|
|
bUser, ok := b.UserKeys[aIndex]
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if !cmpEntry(aUser, bUser) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func TestNewFrom(t *testing.T) {
|
|
records, err := passvault.InitFrom("memory")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
cache := NewCache()
|
|
|
|
users := []string{"alice", "bob", "carol"}
|
|
for _, user := range users {
|
|
pr, err := records.AddNewRecord(user, "weakpassword", true, passvault.DefaultRecordType)
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
|
|
err = cache.AddKeyFromRecord(
|
|
pr, user, "weakpassword",
|
|
[]string{"ci", "buildeng", "user"},
|
|
[]string{"red", "blue"},
|
|
1, "", "1h")
|
|
if err != nil {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
}
|
|
|
|
pr, ok := records.GetRecord("alice")
|
|
if !ok {
|
|
t.Fatal("Couldn't retrieve 'alice' record.")
|
|
}
|
|
|
|
err = cache.AddKeyFromRecord(pr, "alice", "weakpassword",
|
|
[]string{"ci", "alice"}, []string{"blue", "yellow"},
|
|
2, "slotname", "1h")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
summary := cache.GetSummary()
|
|
cache2 := NewFrom(summary)
|
|
if !cmpCache(cache, *cache2) {
|
|
t.Fatal("caches don't match")
|
|
}
|
|
|
|
}
|