| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "crypto/ed25519" |
| 6 | "errors" |
| 7 | "strings" |
| 8 | "testing" |
| 9 | "time" |
| 10 | |
| 11 | "github.com/carlosframework/platform/internal/hostactors" |
| 12 | "github.com/carlosframework/platform/internal/hostbox" |
| 13 | "github.com/carlosframework/platform/internal/hostops" |
| 14 | "github.com/carlosframework/platform/internal/release" |
| 15 | ) |
| 16 | |
| 17 | func TestClaimEvidenceProviderConfiguresOnlyRootSigner(t *testing.T) { |
| 18 | root := ed25519.NewKeyFromSeed(bytes.Repeat([]byte{1}, ed25519.SeedSize)) |
| 19 | private := ed25519.NewKeyFromSeed(bytes.Repeat([]byte{2}, ed25519.SeedSize)) |
| 20 | store := release.NewDirStore(t.TempDir()) |
| 21 | actor := hostbox.Actor{Box: "box", Enrollment: strings.Repeat("a", 32), ControlBucket: "bucket", Bucket: "bucket"} |
| 22 | roster := hostactors.Roster{V: 1, DeploymentBucket: actor.Bucket, Revision: 3, RequestLimitNS: int64(hostbox.RequestLimit), Regions: map[string]hostactors.Region{"ie": {}}, Boxes: map[string]hostactors.Box{ |
| 23 | actor.Box: {CensusPublicKey: private.Public().(ed25519.PublicKey), Enrollment: actor.Enrollment, Namespace: "platform", BoxID: actor.Box, Label: actor.Box, Region: "ie", Pool: "default", Cloud: hostactors.Cloud{Provider: "aws", Account: "123", Region: "ie", InstanceID: "i-box"}, EvidenceSHA256: strings.Repeat("c", 64), State: "active"}, |
| 24 | }, Consoles: map[string]hostactors.Console{}, Holds: map[string]hostactors.Reservation{}, Activations: map[string]hostactors.Reservation{}} |
| 25 | body, err := release.SignRootEnvelope(release.RootSigner(root), roster) |
| 26 | if err != nil { |
| 27 | t.Fatal(err) |
| 28 | } |
| 29 | if _, err := store.Put(t.Context(), hostactors.Key, body, ""); err != nil { |
| 30 | t.Fatal(err) |
| 31 | } |
| 32 | authority := &hostops.ProductionAuthority{Store: store, Directory: hostactors.Directory{Store: store, PublicKey: root.Public().(ed25519.PublicKey), Bucket: actor.Bucket}, Now: time.Now} |
| 33 | owners := ClaimOwnerBindings{RetirementAuthority: authority, EvidenceKey: private} |
| 34 | stop, err := owners.claimEvidenceCoordinator(t.Context(), store, "instance-control", actor) |
| 35 | if err != nil || stop.RequestLimit != hostbox.RequestLimit || !bytes.Equal(stop.EvidenceSigner, private) { |
| 36 | t.Fatalf("root signer: %+v, %v", stop, err) |
| 37 | } |
| 38 | private[0] ^= 1 |
| 39 | if bytes.Equal(stop.EvidenceSigner, private) { |
| 40 | t.Fatal("coordinator retained mutable provider key") |
| 41 | } |
| 42 | private[0] ^= 1 |
| 43 | for _, mode := range []string{"agent", "adopt"} { |
| 44 | if _, err := owners.claimEvidenceCoordinator(t.Context(), store, mode, actor); err == nil { |
| 45 | t.Fatalf("%s accepted a private key", mode) |
| 46 | } |
| 47 | withoutKey := owners |
| 48 | withoutKey.EvidenceKey = nil |
| 49 | stop, err := withoutKey.claimEvidenceCoordinator(t.Context(), store, mode, actor) |
| 50 | if err != nil || len(stop.EvidenceSigner) != 0 { |
| 51 | t.Fatalf("%s needs or retains root key: %+v, %v", mode, stop, err) |
| 52 | } |
| 53 | } |
| 54 | for _, bad := range []ClaimOwnerBindings{ |
| 55 | {}, |
| 56 | {RetirementAuthority: authority}, |
| 57 | {RetirementAuthority: authority, EvidenceKey: root}, |
| 58 | } { |
| 59 | if _, err := bad.claimEvidenceCoordinator(t.Context(), store, "instance-control", actor); err == nil { |
| 60 | t.Fatal("root accepted missing authority or unenrolled key") |
| 61 | } |
| 62 | } |
| 63 | for _, wrongDirectory := range []bool{false, true} { |
| 64 | wrong := *authority |
| 65 | if wrongDirectory { |
| 66 | wrong.Directory.Store = release.NewDirStore(t.TempDir()) |
| 67 | } else { |
| 68 | wrong.Store = release.NewDirStore(t.TempDir()) |
| 69 | } |
| 70 | miswired := owners |
| 71 | miswired.RetirementAuthority = &wrong |
| 72 | if _, err := miswired.claimEvidenceCoordinator(t.Context(), store, "instance-control", actor); err == nil { |
| 73 | t.Fatal("authority accepted another store") |
| 74 | } |
| 75 | } |
| 76 | otherActor := actor |
| 77 | otherActor.Enrollment = strings.Repeat("b", 32) |
| 78 | if _, err := owners.claimEvidenceCoordinator(t.Context(), store, "instance-control", otherActor); !errors.Is(err, ErrClaimStopIdentity) { |
| 79 | t.Fatalf("wrong enrollment accepted: %v", err) |
| 80 | } |
| 81 | otherActor = actor |
| 82 | otherActor.ControlBucket = "other-deployment" |
| 83 | if _, err := owners.claimEvidenceCoordinator(t.Context(), store, "instance-control", otherActor); err == nil { |
| 84 | t.Fatal("wrong deployment accepted") |
| 85 | } |
| 86 | } |
| 87 | |