boxid: a roster entry with no proven cloud does not refuse its own reference; Enroll's caller binds a new reference to its instance
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+30
−6
internal/boxid/boxid_test.go+16 −1internal/boxid/verify.go+14 −5
diff --git a/internal/boxid/boxid_test.go b/internal/boxid/boxid_test.go| index f153f4c49..cc733fd5c 100644 |
| --- a/internal/boxid/boxid_test.go |
| +++ b/internal/boxid/boxid_test.go |
| @@ -1,6 +1,7 @@ |
| package boxid |
| import ( |
| + "bytes" |
| "context" |
| "crypto" |
| "crypto/rand" |
| @@ -122,7 +123,9 @@ func TestEnrollRefusals(t *testing.T) { |
| "reference is not a label": {good(), expect("annie.welding")}, |
| "no expected region": {good(), Expect{Box: "annie-welding"}}, |
| "tofu names another instance": {good(), Expect{Box: "annie-welding", AWSRegion: "eu-west-1", TofuInstanceID: "i-0zzz"}}, |
| - "unknown field in the record": {[]byte(`{"v":1,"box":"annie-welding","extra":1}`), expect("annie-welding")}, |
| + // A good, signed record plus one field: only DisallowUnknownFields |
| + // can refuse it. |
| + "unknown field in the record": {append(bytes.TrimSuffix(good(), []byte("}")), []byte(`,"extra":1}`)...), expect("annie-welding")}, |
| "trailing data": {append(good(), []byte(`{}`)...), expect("annie-welding")}, |
| "version 2": {func() []byte { |
| r, _ := s.record(t, "annie-welding", "111122223333", "eu-west-1", "i-0abc") |
| @@ -219,3 +222,15 @@ func TestEmbeddedCertsCoverTheFlagshipRegions(t *testing.T) { |
| } |
| } |
| } |
| + |
| +// Final review 2: a reference already on the roster with no proven cloud |
| +// yet (a box predating region HA) enrolls once, against its tofu id. Only |
| +// an entry that already names another instance refuses the reference. |
| +func TestEnrollAcceptsARosterEntryWithNoCloudYet(t *testing.T) { |
| + s := newSigner(t) |
| + _, raw := s.record(t, "annie-welding", "111122223333", "eu-west-1", "i-0abc") |
| + roster := []Enrolled{{Box: "annie-welding"}} |
| + if _, err := s.verifier().Enroll(raw, Expect{Box: "annie-welding", AWSRegion: "eu-west-1", TofuInstanceID: "i-0abc", Roster: roster}); err != nil { |
| + t.Fatalf("a roster entry with no cloud yet: %v", err) |
| + } |
| +} |
diff --git a/internal/boxid/verify.go b/internal/boxid/verify.go| index 59dcfe3ce..7b3f816b9 100644 |
| --- a/internal/boxid/verify.go |
| +++ b/internal/boxid/verify.go |
| @@ -86,10 +86,19 @@ func decodeRecord(raw []byte) (Record, error) { |
| // field, AWS's signature under the certificate for the document's region, |
| // the deployment account, the AWS region expected for the placement, the |
| // tofu instance id for a reference predating region HA, and the roster: |
| -// the reference enrolled as another instance, or the instance enrolled |
| -// under another reference, is refused. A record copied from one box to |
| -// another's key carries the first box's signed instance id, so the last |
| -// check is what keeps one machine from holding two references. |
| +// the reference already enrolled as another instance, or the instance |
| +// enrolled under another reference, is refused. A roster entry for the |
| +// reference with no proven cloud yet does not refuse it. A record copied |
| +// from one box to another's key carries the first box's signed instance |
| +// id, so the last check is what keeps one machine from holding two |
| +// references. |
| +// |
| +// The record's box field is not covered by AWS's signature: anything that |
| +// can write the key can name any reference. For a reference the roster |
| +// does not yet hold, Enroll proves only that some instance of the |
| +// deployment wrote the record, so the caller must bind that instance to |
| +// the reference independently (operator approval, the tofu id, or H16's |
| +// group confirmation) before enrolling it. |
| func (v Verifier) Enroll(raw []byte, e Expect) (Evidence, error) { |
| if !ValidBox(e.Box) { |
| return Evidence{}, refuse("%q is not a box reference", e.Box) |
| @@ -141,7 +150,7 @@ func (v Verifier) Enroll(raw []byte, e Expect) (Evidence, error) { |
| return Evidence{}, refuse("tofu records instance %q for this region, the record %q", e.TofuInstanceID, d.InstanceID) |
| } |
| for _, en := range e.Roster { |
| - if en.Box == e.Box && en.Cloud.InstanceID != d.InstanceID { |
| + if en.Box == e.Box && en.Cloud.InstanceID != "" && en.Cloud.InstanceID != d.InstanceID { |
| return Evidence{}, refuse("%s is enrolled as instance %q", e.Box, en.Cloud.InstanceID) |
| } |
| if en.Box != e.Box && en.Cloud.InstanceID == d.InstanceID { |