mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-07-24 17:12:52 +00:00
Changes to delegation model
- decryption can happen by non-admins - encrypted files can be given labels - delegation can limit decryption to specific users and labels
This commit is contained in:
+10
-7
@@ -34,8 +34,10 @@ type delegate struct {
|
|||||||
Name string
|
Name string
|
||||||
Password string
|
Password string
|
||||||
|
|
||||||
Uses int
|
Uses int
|
||||||
Time string
|
Time string
|
||||||
|
Users []string
|
||||||
|
Labels []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type password struct {
|
type password struct {
|
||||||
@@ -54,6 +56,8 @@ type encrypt struct {
|
|||||||
LeftOwners []string
|
LeftOwners []string
|
||||||
RightOwners []string
|
RightOwners []string
|
||||||
Data []byte
|
Data []byte
|
||||||
|
|
||||||
|
Labels []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type decrypt struct {
|
type decrypt struct {
|
||||||
@@ -228,7 +232,7 @@ func Delegate(jsonIn []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add signed-in record to active set
|
// add signed-in record to active set
|
||||||
if err := keycache.AddKeyFromRecord(pr, s.Name, s.Password, s.Uses, s.Time); err != nil {
|
if err := keycache.AddKeyFromRecord(pr, s.Name, s.Password, s.Users, s.Labels, s.Uses, s.Time); err != nil {
|
||||||
log.Printf("Error adding key to cache for %s: %s\n", s.Name, err)
|
log.Printf("Error adding key to cache for %s: %s\n", s.Name, err)
|
||||||
return jsonStatusError(err)
|
return jsonStatusError(err)
|
||||||
}
|
}
|
||||||
@@ -274,7 +278,7 @@ func Encrypt(jsonIn []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt file with list of owners
|
// Encrypt file with list of owners
|
||||||
if resp, err := cryptor.Encrypt(s.Data, s.LeftOwners, s.RightOwners, s.Minimum); err != nil {
|
if resp, err := cryptor.Encrypt(s.Data, s.Labels, s.LeftOwners, s.RightOwners, s.Minimum); err != nil {
|
||||||
log.Println("Error encrypting:", err)
|
log.Println("Error encrypting:", err)
|
||||||
return jsonStatusError(err)
|
return jsonStatusError(err)
|
||||||
} else {
|
} else {
|
||||||
@@ -290,13 +294,12 @@ func Decrypt(jsonIn []byte) ([]byte, error) {
|
|||||||
return jsonStatusError(err)
|
return jsonStatusError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = validateAdmin(s.Name, s.Password)
|
err = validateUser(s.Name, s.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error validating admin status", err)
|
|
||||||
return jsonStatusError(err)
|
return jsonStatusError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, names, err := cryptor.Decrypt(s.Data)
|
data, names, err := cryptor.Decrypt(s.Data, s.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error decrypting:", err)
|
log.Println("Error decrypting:", err)
|
||||||
return jsonStatusError(err)
|
return jsonStatusError(err)
|
||||||
|
|||||||
+3
-3
@@ -288,10 +288,10 @@ func TestEncryptDecrypt(t *testing.T) {
|
|||||||
delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
|
delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
|
||||||
delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
|
delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
|
||||||
delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
|
delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
|
||||||
delegateJson4 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2}")
|
delegateJson4 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2,\"Users\":[\"Alice\"],\"Labels\":[\"blue\"]}")
|
||||||
delegateJson5 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2}")
|
delegateJson5 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2,\"Users\":[\"Alice\"],\"Labels\":[\"blue\"]}")
|
||||||
encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
|
encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
|
||||||
encryptJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
|
encryptJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\",\"Labels\":[\"blue\",\"red\"]}")
|
||||||
os.Remove("/tmp/db1.json")
|
os.Remove("/tmp/db1.json")
|
||||||
|
|
||||||
Init("/tmp/db1.json")
|
Init("/tmp/db1.json")
|
||||||
|
|||||||
+16
-5
@@ -45,6 +45,7 @@ type SingleWrappedKey struct {
|
|||||||
type EncryptedData struct {
|
type EncryptedData struct {
|
||||||
Version int
|
Version int
|
||||||
VaultId int
|
VaultId int
|
||||||
|
Labels []string
|
||||||
KeySet []MultiWrappedKey
|
KeySet []MultiWrappedKey
|
||||||
KeySetRSA map[string]SingleWrappedKey
|
KeySetRSA map[string]SingleWrappedKey
|
||||||
IV []byte
|
IV []byte
|
||||||
@@ -112,7 +113,7 @@ func encryptKey(nameInner, nameOuter string, clearKey []byte, pubKeys map[string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unwrapKey decrypts first key in keys whose encryption keys are in keycache
|
// unwrapKey decrypts first key in keys whose encryption keys are in keycache
|
||||||
func unwrapKey(keys []MultiWrappedKey, pubKeys map[string]SingleWrappedKey) (unwrappedKey []byte, names []string, err error) {
|
func unwrapKey(keys []MultiWrappedKey, pubKeys map[string]SingleWrappedKey, user string, labels []string) (unwrappedKey []byte, names []string, err error) {
|
||||||
var (
|
var (
|
||||||
keyFound error
|
keyFound error
|
||||||
fullMatch bool = false
|
fullMatch bool = false
|
||||||
@@ -129,7 +130,7 @@ func unwrapKey(keys []MultiWrappedKey, pubKeys map[string]SingleWrappedKey) (unw
|
|||||||
for _, mwName := range mwKey.Name {
|
for _, mwName := range mwKey.Name {
|
||||||
pubEncrypted := pubKeys[mwName]
|
pubEncrypted := pubKeys[mwName]
|
||||||
// if this is null, it's an AES encrypted key
|
// if this is null, it's an AES encrypted key
|
||||||
if tmpKeyValue, keyFound = keycache.DecryptKey(tmpKeyValue, mwName, pubEncrypted.Key); keyFound != nil {
|
if tmpKeyValue, keyFound = keycache.DecryptKey(tmpKeyValue, mwName, user, labels, pubEncrypted.Key); keyFound != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
nameSet[mwName] = true
|
nameSet[mwName] = true
|
||||||
@@ -227,6 +228,9 @@ func computeHmac(key []byte, encrypted EncryptedData) []byte {
|
|||||||
}
|
}
|
||||||
sort.Sort(&swks)
|
sort.Sort(&swks)
|
||||||
|
|
||||||
|
// sort the labels
|
||||||
|
sort.Strings(encrypted.Labels)
|
||||||
|
|
||||||
// start hashing
|
// start hashing
|
||||||
mac.Write([]byte(strconv.Itoa(encrypted.Version)))
|
mac.Write([]byte(strconv.Itoa(encrypted.Version)))
|
||||||
mac.Write([]byte(strconv.Itoa(encrypted.VaultId)))
|
mac.Write([]byte(strconv.Itoa(encrypted.VaultId)))
|
||||||
@@ -249,13 +253,18 @@ func computeHmac(key []byte, encrypted EncryptedData) []byte {
|
|||||||
mac.Write(encrypted.IV)
|
mac.Write(encrypted.IV)
|
||||||
mac.Write(encrypted.Data)
|
mac.Write(encrypted.Data)
|
||||||
|
|
||||||
|
// hash the labels
|
||||||
|
for index := range encrypted.Labels {
|
||||||
|
mac.Write([]byte(encrypted.Labels[index]))
|
||||||
|
}
|
||||||
|
|
||||||
return mac.Sum(nil)
|
return mac.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt encrypts data with the keys associated with names. This
|
// Encrypt encrypts data with the keys associated with names. This
|
||||||
// requires a minimum of min keys to decrypt. NOTE: as currently
|
// requires a minimum of min keys to decrypt. NOTE: as currently
|
||||||
// implemented, the maximum value for min is 2.
|
// implemented, the maximum value for min is 2.
|
||||||
func Encrypt(in []byte, leftNames, rightNames []string, min int) (resp []byte, err error) {
|
func Encrypt(in []byte, labels, leftNames, rightNames []string, min int) (resp []byte, err error) {
|
||||||
if min > 2 {
|
if min > 2 {
|
||||||
return nil, errors.New("Minimum restricted to 2")
|
return nil, errors.New("Minimum restricted to 2")
|
||||||
}
|
}
|
||||||
@@ -358,6 +367,7 @@ func Encrypt(in []byte, leftNames, rightNames []string, min int) (resp []byte, e
|
|||||||
aesCBC.CryptBlocks(encryptedFile, clearFile)
|
aesCBC.CryptBlocks(encryptedFile, clearFile)
|
||||||
|
|
||||||
encrypted.Data = encryptedFile
|
encrypted.Data = encryptedFile
|
||||||
|
encrypted.Labels = labels
|
||||||
|
|
||||||
hmacKey, err := passvault.GetHmacKey()
|
hmacKey, err := passvault.GetHmacKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -369,7 +379,7 @@ func Encrypt(in []byte, leftNames, rightNames []string, min int) (resp []byte, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt decrypts a file using the keys in the key cache.
|
// Decrypt decrypts a file using the keys in the key cache.
|
||||||
func Decrypt(in []byte) (resp []byte, names []string, err error) {
|
func Decrypt(in []byte, user string) (resp []byte, names []string, err error) {
|
||||||
// unwrap encrypted file
|
// unwrap encrypted file
|
||||||
var encrypted EncryptedData
|
var encrypted EncryptedData
|
||||||
if err = json.Unmarshal(in, &encrypted); err != nil {
|
if err = json.Unmarshal(in, &encrypted); err != nil {
|
||||||
@@ -409,7 +419,8 @@ func Decrypt(in []byte) (resp []byte, names []string, err error) {
|
|||||||
|
|
||||||
// decrypt file key with delegate keys
|
// decrypt file key with delegate keys
|
||||||
var unwrappedKey = make([]byte, 16)
|
var unwrappedKey = make([]byte, 16)
|
||||||
if unwrappedKey, names, err = unwrapKey(encrypted.KeySet, encrypted.KeySetRSA); err != nil {
|
unwrappedKey, names, err = unwrapKey(encrypted.KeySet, encrypted.KeySetRSA, user, encrypted.Labels)
|
||||||
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+75
-21
@@ -12,21 +12,29 @@ import (
|
|||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/cloudflare/redoctober/ecdh"
|
|
||||||
"github.com/cloudflare/redoctober/passvault"
|
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cloudflare/redoctober/ecdh"
|
||||||
|
"github.com/cloudflare/redoctober/passvault"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserKeys is the set of decrypted keys in memory, indexed by name.
|
// UserKeys is the set of decrypted keys in memory, indexed by name.
|
||||||
var UserKeys map[string]ActiveUser = make(map[string]ActiveUser)
|
var UserKeys map[string]ActiveUser = make(map[string]ActiveUser)
|
||||||
|
|
||||||
|
// Usage holds the permissions of a delegated permission
|
||||||
|
type Usage struct {
|
||||||
|
Uses int // Number of uses delegated
|
||||||
|
Labels []string // File labels allowed to decrypt
|
||||||
|
Users []string // Set of users allows to decrypt
|
||||||
|
Expiry time.Time // Expiration of usage
|
||||||
|
}
|
||||||
|
|
||||||
// ActiveUser holds the information about an actively delegated key.
|
// ActiveUser holds the information about an actively delegated key.
|
||||||
type ActiveUser struct {
|
type ActiveUser struct {
|
||||||
Admin bool
|
Usage
|
||||||
Type string
|
Admin bool
|
||||||
Expiry time.Time
|
Type string
|
||||||
Uses int
|
|
||||||
|
|
||||||
aesKey []byte
|
aesKey []byte
|
||||||
rsaKey rsa.PrivateKey
|
rsaKey rsa.PrivateKey
|
||||||
@@ -35,8 +43,16 @@ type ActiveUser struct {
|
|||||||
|
|
||||||
// matchUser returns the matching active user if present
|
// matchUser returns the matching active user if present
|
||||||
// and a boolean to indicate its presence.
|
// and a boolean to indicate its presence.
|
||||||
func matchUser(name string) (out ActiveUser, present bool) {
|
func matchUser(name, user string, labels []string) (out ActiveUser, present bool) {
|
||||||
out, present = UserKeys[name]
|
key, present := UserKeys[name]
|
||||||
|
if present {
|
||||||
|
if key.Usage.matches(user, labels) {
|
||||||
|
return key, true
|
||||||
|
} else {
|
||||||
|
present = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,11 +61,47 @@ func setUser(in ActiveUser, name string) {
|
|||||||
UserKeys[name] = in
|
UserKeys[name] = in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// matchesLabel returns true if this usage applies the user and label
|
||||||
|
// an empty array of Users indicates that all users are valid
|
||||||
|
func (usage Usage) matchesLabel(labels []string) bool {
|
||||||
|
// if asset has no labels always match
|
||||||
|
if len(labels) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
//
|
||||||
|
for _, validLabel := range usage.Labels {
|
||||||
|
for _, label := range labels {
|
||||||
|
if label == validLabel {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// matches returns true if this usage applies the user and label
|
||||||
|
// an empty array of Users indicates that all users are valid
|
||||||
|
func (usage Usage) matches(user string, labels []string) bool {
|
||||||
|
if !usage.matchesLabel(labels) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// if usage lists no users, always match
|
||||||
|
if len(usage.Users) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, validUser := range usage.Users {
|
||||||
|
if user == validUser {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// useKey decrements the counter on an active key
|
// useKey decrements the counter on an active key
|
||||||
// for decryption or symmetric encryption
|
// for decryption or symmetric encryption
|
||||||
func useKey(name string) {
|
func useKey(name, user string, labels []string) {
|
||||||
if val, present := matchUser(name); present {
|
if val, present := matchUser(name, user, labels); present {
|
||||||
val.Uses -= 1
|
val.Usage.Uses -= 1
|
||||||
setUser(val, name)
|
setUser(val, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,15 +121,15 @@ func FlushCache() {
|
|||||||
// Refresh purges all expired or used up keys.
|
// Refresh purges all expired or used up keys.
|
||||||
func Refresh() {
|
func Refresh() {
|
||||||
for name, active := range UserKeys {
|
for name, active := range UserKeys {
|
||||||
if active.Expiry.Before(time.Now()) || active.Uses <= 0 {
|
if active.Usage.Expiry.Before(time.Now()) || active.Usage.Uses <= 0 {
|
||||||
log.Println("Record expired", name, active.Expiry)
|
log.Println("Record expired", name, active.Usage.Users, active.Usage.Labels, active.Usage.Expiry)
|
||||||
delete(UserKeys, name)
|
delete(UserKeys, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddKeyFromRecord decrypts a key for a given record and adds it to the cache.
|
// AddKeyFromRecord decrypts a key for a given record and adds it to the cache.
|
||||||
func AddKeyFromRecord(record passvault.PasswordRecord, name string, password string, uses int, durationString string) (err error) {
|
func AddKeyFromRecord(record passvault.PasswordRecord, name, password string, users, labels []string, uses int, durationString string) (err error) {
|
||||||
var current ActiveUser
|
var current ActiveUser
|
||||||
|
|
||||||
Refresh()
|
Refresh()
|
||||||
@@ -87,8 +139,10 @@ func AddKeyFromRecord(record passvault.PasswordRecord, name string, password str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
current.Uses = uses
|
current.Usage.Uses = uses
|
||||||
current.Expiry = time.Now().Add(duration)
|
current.Usage.Expiry = time.Now().Add(duration)
|
||||||
|
current.Usage.Users = users
|
||||||
|
current.Usage.Labels = labels
|
||||||
|
|
||||||
// get decryption keys
|
// get decryption keys
|
||||||
switch record.Type {
|
switch record.Type {
|
||||||
@@ -127,7 +181,7 @@ func EncryptKey(in []byte, name string, override []byte) (out []byte, err error)
|
|||||||
|
|
||||||
// if the override key is not set, extract from the cache
|
// if the override key is not set, extract from the cache
|
||||||
if aesKey == nil {
|
if aesKey == nil {
|
||||||
encryptKey, ok := matchUser(name)
|
encryptKey, ok := matchUser(name, name, []string{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("Key not delegated")
|
return nil, errors.New("Key not delegated")
|
||||||
}
|
}
|
||||||
@@ -140,7 +194,7 @@ func EncryptKey(in []byte, name string, override []byte) (out []byte, err error)
|
|||||||
return out, errors.New("Require override for key")
|
return out, errors.New("Require override for key")
|
||||||
}
|
}
|
||||||
|
|
||||||
useKey(name)
|
useKey(name, name, []string{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt
|
// encrypt
|
||||||
@@ -159,10 +213,10 @@ func EncryptKey(in []byte, name string, override []byte) (out []byte, err error)
|
|||||||
// for RSA and EC keys, the cached RSA/EC key is used to decrypt
|
// for RSA and EC keys, the cached RSA/EC key is used to decrypt
|
||||||
// the pubEncryptedKey which is then used to decrypt the input
|
// the pubEncryptedKey which is then used to decrypt the input
|
||||||
// buffer.
|
// buffer.
|
||||||
func DecryptKey(in []byte, name string, pubEncryptedKey []byte) (out []byte, err error) {
|
func DecryptKey(in []byte, name, user string, labels []string, pubEncryptedKey []byte) (out []byte, err error) {
|
||||||
Refresh()
|
Refresh()
|
||||||
|
|
||||||
decryptKey, ok := matchUser(name)
|
decryptKey, ok := matchUser(name, user, labels)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("Key not delegated")
|
return nil, errors.New("Key not delegated")
|
||||||
}
|
}
|
||||||
@@ -199,7 +253,7 @@ func DecryptKey(in []byte, name string, pubEncryptedKey []byte) (out []byte, err
|
|||||||
out = make([]byte, 16)
|
out = make([]byte, 16)
|
||||||
aesSession.Decrypt(out, in)
|
aesSession.Decrypt(out, in)
|
||||||
|
|
||||||
useKey(name)
|
useKey(name, user, labels)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+162
-10
@@ -16,10 +16,12 @@ var dummy = make([]byte, 16)
|
|||||||
|
|
||||||
func TestUsesFlush(t *testing.T) {
|
func TestUsesFlush(t *testing.T) {
|
||||||
singleUse := ActiveUser{
|
singleUse := ActiveUser{
|
||||||
Admin: true,
|
Admin: true,
|
||||||
Type: passvault.AESRecord,
|
Type: passvault.AESRecord,
|
||||||
Expiry: nextYear,
|
Usage: Usage{
|
||||||
Uses: 2,
|
Expiry: nextYear,
|
||||||
|
Uses: 2,
|
||||||
|
},
|
||||||
aesKey: emptyKey,
|
aesKey: emptyKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ func TestUsesFlush(t *testing.T) {
|
|||||||
t.Fatalf("Error in number of live keys %v", UserKeys)
|
t.Fatalf("Error in number of live keys %v", UserKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
DecryptKey(dummy, "first", nil)
|
DecryptKey(dummy, "first", "", []string{}, nil)
|
||||||
|
|
||||||
Refresh()
|
Refresh()
|
||||||
if len(UserKeys) != 0 {
|
if len(UserKeys) != 0 {
|
||||||
@@ -50,10 +52,12 @@ func TestTimeFlush(t *testing.T) {
|
|||||||
one := now.Add(oneSec)
|
one := now.Add(oneSec)
|
||||||
|
|
||||||
singleUse := ActiveUser{
|
singleUse := ActiveUser{
|
||||||
Admin: true,
|
Admin: true,
|
||||||
Type: passvault.AESRecord,
|
Type: passvault.AESRecord,
|
||||||
Expiry: one,
|
Usage: Usage{
|
||||||
Uses: 10,
|
Expiry: one,
|
||||||
|
Uses: 10,
|
||||||
|
},
|
||||||
aesKey: emptyKey,
|
aesKey: emptyKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,9 +77,157 @@ func TestTimeFlush(t *testing.T) {
|
|||||||
|
|
||||||
time.Sleep(oneSec)
|
time.Sleep(oneSec)
|
||||||
|
|
||||||
_, err := DecryptKey(dummy, "first", nil)
|
_, err := DecryptKey(dummy, "first", "", []string{}, nil)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Error in pruning expired key")
|
t.Fatalf("Error in pruning expired key")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGoodLabel(t *testing.T) {
|
||||||
|
singleUse := ActiveUser{
|
||||||
|
Admin: true,
|
||||||
|
Type: passvault.AESRecord,
|
||||||
|
Usage: Usage{
|
||||||
|
Expiry: nextYear,
|
||||||
|
Uses: 2,
|
||||||
|
Labels: []string{"red"},
|
||||||
|
},
|
||||||
|
aesKey: emptyKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
UserKeys["first"] = singleUse
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptKey(dummy, "first", nil)
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
DecryptKey(dummy, "first", "", []string{"red"}, nil)
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 0 {
|
||||||
|
t.Fatalf("Error in number of live keys %v", UserKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBadLabel(t *testing.T) {
|
||||||
|
singleUse := ActiveUser{
|
||||||
|
Admin: true,
|
||||||
|
Type: passvault.AESRecord,
|
||||||
|
Usage: Usage{
|
||||||
|
Expiry: nextYear,
|
||||||
|
Uses: 2,
|
||||||
|
Labels: []string{"red"},
|
||||||
|
},
|
||||||
|
aesKey: emptyKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
UserKeys["first"] = singleUse
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptKey(dummy, "first", nil)
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := DecryptKey(dummy, "first", "", []string{"blue"}, nil)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Decryption of labeled key with no permission")
|
||||||
|
}
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys %v", UserKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoodUser(t *testing.T) {
|
||||||
|
singleUse := ActiveUser{
|
||||||
|
Admin: true,
|
||||||
|
Type: passvault.AESRecord,
|
||||||
|
Usage: Usage{
|
||||||
|
Expiry: nextYear,
|
||||||
|
Uses: 2,
|
||||||
|
Users: []string{"ci", "buildeng", "first"},
|
||||||
|
Labels: []string{"red", "blue"},
|
||||||
|
},
|
||||||
|
aesKey: emptyKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
UserKeys["first"] = singleUse
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptKey(dummy, "first", nil)
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
DecryptKey(dummy, "first", "ci", []string{"red"}, nil)
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 0 {
|
||||||
|
t.Fatalf("Error in number of live keys %v", UserKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBadUser(t *testing.T) {
|
||||||
|
singleUse := ActiveUser{
|
||||||
|
Admin: true,
|
||||||
|
Type: passvault.AESRecord,
|
||||||
|
Usage: Usage{
|
||||||
|
Expiry: nextYear,
|
||||||
|
Uses: 2,
|
||||||
|
Users: []string{"ci", "buildeng", "first"},
|
||||||
|
Labels: []string{"red", "blue"},
|
||||||
|
},
|
||||||
|
aesKey: emptyKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
UserKeys["first"] = singleUse
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the active user needs to be in the set of delegated
|
||||||
|
// users in the AES case only
|
||||||
|
EncryptKey(dummy, "first", nil)
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := DecryptKey(dummy, "first", "", []string{"blue"}, nil)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Decryption of labeled key by unauthorized user")
|
||||||
|
}
|
||||||
|
|
||||||
|
Refresh()
|
||||||
|
if len(UserKeys) != 1 {
|
||||||
|
t.Fatalf("Error in number of live keys %v", UserKeys)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user