From 9ca4b300faeb27f186f81a5002f1c61a1dfd7656 Mon Sep 17 00:00:00 2001 From: Keith Fong Date: Tue, 8 Sep 2026 12:13:10 +0800 Subject: [PATCH] SEC-1151 enforce KEK bundle completeness Reject AES and TripleDES key merges until every declared component has been imported. Add collision-shaped regression coverage for both key types.\n\nCo-Authored-By: Claude --- kek/kek_bundle.go | 8 ++++++++ kek/kek_bundle_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/kek/kek_bundle.go b/kek/kek_bundle.go index 4efb043..d1308dc 100644 --- a/kek/kek_bundle.go +++ b/kek/kek_bundle.go @@ -103,6 +103,10 @@ func (b *Bundle) Merge() (des.Cipher, error) { // MergeTripleDESKey tries to build the result TripleDES key from all the imported components func (b *Bundle) MergeTripleDESKey() (des.Cipher, error) { + if !b.IsComplete() { + return des.Cipher{}, fmt.Errorf("incomplete KEK bundle: expected %d components but got %d", b.Size, len(b.Components)) + } + kekBytes := make([]byte, 24) for _, component := range b.Components { kekBytes, _ = xor.XORBytes(kekBytes, component) @@ -121,6 +125,10 @@ func (b *Bundle) MergeTripleDESKey() (des.Cipher, error) { // MergeAESKey tries to build the result AES key from all the imported components func (b *Bundle) MergeAESKey() (aes.Cipher, error) { + if !b.IsComplete() { + return aes.Cipher{}, fmt.Errorf("incomplete KEK bundle: expected %d components but got %d", b.Size, len(b.Components)) + } + var keyLen int for _, component := range b.Components { if keyLen == 0 { diff --git a/kek/kek_bundle_test.go b/kek/kek_bundle_test.go index f974c35..f99b0e7 100644 --- a/kek/kek_bundle_test.go +++ b/kek/kek_bundle_test.go @@ -118,6 +118,23 @@ func TestMergeResultKeySuccess(t *testing.T) { } } +func TestMergeTripleDESKeyRejectsIncompleteBundleWithMatchingCheckValue(t *testing.T) { + kek := New("visa", 1, 3, "DD1375") + + err := kek.AddComponent(1, "E38FD6D9EF85A892F2FBFDD083A407AE", "DD1375") + if err != nil { + t.Fatalf("adding component failed with %v", err) + } + + _, err = kek.MergeTripleDESKey() + if err == nil { + t.Fatal("should have failed if the bundle is incomplete") + } + if err.Error() != "incomplete KEK bundle: expected 3 components but got 1" { + t.Fatalf("unexpected error: %v", err) + } +} + // AES KEK tests func TestAESAddComponentInvalidValue(t *testing.T) { @@ -174,6 +191,23 @@ func TestAESMergeAESKeySuccess(t *testing.T) { } } +func TestMergeAESKeyRejectsIncompleteBundleWithMatchingCheckValue(t *testing.T) { + kek := NewWithKeyType("aes-kek", 1, 3, "B1DD24", KeyTypeAES) + + err := kek.AddComponent(1, "574953452d504f430000000000546263", "B1DD24") + if err != nil { + t.Fatalf("adding component failed with %v", err) + } + + _, err = kek.MergeAESKey() + if err == nil { + t.Fatal("should have failed if the bundle is incomplete") + } + if err.Error() != "incomplete KEK bundle: expected 3 components but got 1" { + t.Fatalf("unexpected error: %v", err) + } +} + func TestAESMergeAESKeyCheckValueNotTally(t *testing.T) { kek := NewWithKeyType("aes-kek", 1, 3, "FFFFFF", KeyTypeAES)