From review: the export counted any operator-sealed row as recoverable, so a secret sealed to a replaced key was reported as openable with the current one; replacing the key counted orphans in one table of two; and a pair credential held from two providers was recovered as whichever row came first. The export now lists what the current key opens, what an earlier key opens, and what has no copy; `secret recover` takes --provider and refuses ambiguity; files that must not exist are created exclusively; one constructor builds the export for the operator's file and the vault's disk alike.
76 lines
2.0 KiB
Go
76 lines
2.0 KiB
Go
package secrets
|
|
|
|
import "testing"
|
|
|
|
// A secret sealed to the operator as well is opened by the operator's key and by nothing else.
|
|
func TestAThirdRecipientOpensWithItsOwnKeyOnly(t *testing.T) {
|
|
nodePub, nodePriv, err := Keypair()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
opPub, opPriv, err := Keypair()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sealed, forOperator, err := MakeWithOperator(nodePub, nodePub, opPub)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if forOperator == "" {
|
|
t.Fatal("no blob for the operator")
|
|
}
|
|
if _, none, err := MakeWithOperator(nodePub, nodePub, ""); err != nil || none != "" {
|
|
t.Fatalf("no operator key, yet a blob %q (%v)", none, err)
|
|
}
|
|
fromNode, err := Open(nodePriv, sealed.ForConsumer)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fromOperator, err := Open(opPriv, forOperator)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(fromNode) != string(fromOperator) {
|
|
t.Fatal("the operator's copy is a different value from the node's")
|
|
}
|
|
if len(fromNode) != 40 {
|
|
t.Fatalf("a minted value is %d characters, not 40", len(fromNode))
|
|
}
|
|
if _, err := Open(nodePriv, forOperator); err == nil {
|
|
t.Fatal("the node's key opened the operator's blob")
|
|
}
|
|
if _, err := Open(opPriv, sealed.ForConsumer); err == nil {
|
|
t.Fatal("the operator's key opened the node's blob")
|
|
}
|
|
}
|
|
|
|
// An accepted value, sealed to the operator, comes back byte for byte.
|
|
func TestAnAcceptedValueRoundTripsThroughTheOperatorKey(t *testing.T) {
|
|
opPub, opPriv, err := Keypair()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
blob, err := Seal(opPub, []byte(" the-superuser's password, spaces and all "))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := Open(opPriv, blob)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != " the-superuser's password, spaces and all " {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestAFingerprintNamesAKeyAndIsNotOne(t *testing.T) {
|
|
pub, _, _ := Keypair()
|
|
fp := Fingerprint(pub)
|
|
if len(fp) != len("sha256:")+16 || fp[:7] != "sha256:" {
|
|
t.Fatalf("fingerprint %q", fp)
|
|
}
|
|
if fp == Fingerprint(pub+"x") {
|
|
t.Fatal("two keys, one fingerprint")
|
|
}
|
|
}
|