diff --git a/CITATION.cff b/CITATION.cff index ae907fef..5ab6a763 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,6 +1,6 @@ --- cff-version: 1.2.0 -version: 1.6.3 +version: 1.6.4 title: "Introducing CIRCL: An Advanced Cryptographic Library" license: BSD-3-Clause abstract: > @@ -25,6 +25,6 @@ keywords: - golang repository-code: "https://github.com/cloudflare/circl/" type: software -message: "Available at https://github.com/cloudflare/circl. v1.6.3 Accessed Jan, 2026." +message: "Available at https://github.com/cloudflare/circl. v1.6.4 Accessed Jun, 2026." contact: - name: "Cloudflare, Inc." diff --git a/README.md b/README.md index c4e2220e..13d7fd1f 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ APA Style ``` Faz-Hernandez, A. and Kwiatkowski, K. (2019). Introducing CIRCL: An Advanced Cryptographic Library. Cloudflare. Available at -https://github.com/cloudflare/circl. v1.6.3 Accessed Jan, 2026. +https://github.com/cloudflare/circl. v1.6.4 Accessed Jun, 2026. ``` BibTeX Source @@ -182,7 +182,7 @@ BibTeX Source of this library is to be used as a tool for experimental deployment of cryptographic algorithms targeting Post-Quantum (PQ) and Elliptic Curve Cryptography (ECC).}}, - note = {Available at \url{https://github.com/cloudflare/circl}. v1.6.3 Accessed Jan, 2026}, + note = {Available at \url{https://github.com/cloudflare/circl}. v1.6.4 Accessed Jun, 2026}, month = jun, year = {2019} } diff --git a/abe/cpabe/tkn20/internal/tkn/formula.go b/abe/cpabe/tkn20/internal/tkn/formula.go index 69ca7533..39a9f755 100644 --- a/abe/cpabe/tkn20/internal/tkn/formula.go +++ b/abe/cpabe/tkn20/internal/tkn/formula.go @@ -86,6 +86,11 @@ func (f *Formula) UnmarshalBinary(data []byte) error { f.Gates[i].In1 = int(binary.LittleEndian.Uint16(data[7*i+2+3:])) f.Gates[i].Out = int(binary.LittleEndian.Uint16(data[7*i+2+5:])) } + // Reject malformed or cyclic gate graphs coming from untrusted encodings. + check := Formula{Gates: append([]Gate(nil), f.Gates...)} + if err := check.toposort(); err != nil { + return fmt.Errorf("invalid formula: %w", err) + } return nil } diff --git a/abe/cpabe/tkn20/tkn20_test.go b/abe/cpabe/tkn20/tkn20_test.go index d699564a..1a6ca63b 100644 --- a/abe/cpabe/tkn20/tkn20_test.go +++ b/abe/cpabe/tkn20/tkn20_test.go @@ -479,3 +479,51 @@ func TestTruncatedCiphertextHeaderPanic(t *testing.T) { t.Error("Decrypt accepted a malformed ciphertext") } } + +func TestPolicyExtractMutatedCiphertextStackOverflow(t *testing.T) { + pk, _, err := Setup(rand.Reader) + if err != nil { + t.Fatal(err) + } + var policy Policy + if err = policy.FromString("(country: US) and (region: EU)"); err != nil { + t.Fatal(err) + } + ct, err := pk.Encrypt(rand.Reader, policy, []byte("secret")) + if err != nil { + t.Fatal(err) + } + // One-gate formula serialization inside the ciphertext header: + // nGates(uint16) | class(byte) | In0(uint16) | In1(uint16) | Out(uint16), little-endian. + patterns := [][]byte{ + {0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00}, // In0=0, In1=1, Out=2 + {0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00}, // In0=1, In1=0, Out=2 + } + idx := -1 + for _, p := range patterns { + if i := bytes.Index(ct, p); i >= 0 { + idx = i + break + } + } + if idx < 0 { + t.Fatal("gate encoding not found in ciphertext") + } + // Attacker mutation: 2 bytes, set the gate's In0 := 2 (its own output wire). + // Observed at offset 52+3=55 in the v1.3.8 ciphertext format. + ct[idx+3] = 0x02 + ct[idx+4] = 0x00 + + var extracted Policy + if err := extracted.ExtractFromCiphertext(ct); err == nil { + t.Fatal("ExtractFromCiphertext() accepted a ciphertext with an invalid gate topology") + } + // Walking this graph would cause a stack overflow: + //defer func() { + // if r := recover(); r != nil { + // t.Logf("recovered (does NOT happen for stack overflow): %v", r) + // } + //}() + //_ = extracted.String() // fatal error: stack overflow — kills the entire process + //t.Fatal("unreachable: String() should have crashed the process") +}