[SCITT] First-failure list: draft-dogru-cedulon-04
Tiago Pinto <tiago@donttrustverify.pt> Sun, 30 August 2026 15:23 UTC
Return-Path: <tiago@donttrustverify.pt>
X-Original-To: scitt@mail2.ietf.org
Delivered-To: scitt@mail2.ietf.org
Received: from localhost (localhost [127.0.0.1]) by mail2.ietf.org (Postfix) with ESMTP id 2F63C131D5214 for <scitt@mail2.ietf.org>; Sun, 30 Aug 2026 08:23:46 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ietf.org; s=ietf1; t=1788103426; bh=phpzFPYgibL/9iqcW08A/39D+L89gsYZPHR+xjnnovk=; h=Date:To:From:Cc:Subject; b=yTXLqGSqzYOOO4RoY6D/7exVPozylq5NZ0m2XZ3iyzE+dFMvRYqSUxcW4mW18kBO2 TwTHZbcpoKrZJhCgk6DIfTXkkxezZIMCJRGqqyGRUDP3ZMnZ4q8uPv8sNrHb3tslmc Ev6AKRW7jNf4wJ4h3bQgMqQ1yrT5nOnJrDHflHCI=
X-Virus-Scanned: amavisd-new at ietf.org
X-Spam-Flag: NO
X-Spam-Score: -2.797
X-Spam-Level:
X-Spam-Status: No, score=-2.797 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: mail2.ietf.org (amavisd-new); dkim=pass (2048-bit key) header.d=donttrustverify.pt
Received: from mail2.ietf.org ([166.84.6.31]) by localhost (mail2.ietf.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1SVBLp0EgXyE for <scitt@mail2.ietf.org>; Sun, 30 Aug 2026 08:23:43 -0700 (PDT)
Received: from mail-4317.protonmail.ch (mail-4317.protonmail.ch [185.70.43.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mail2.ietf.org (Postfix) with ESMTPS id D0CDA131D520F for <scitt@ietf.org>; Sun, 30 Aug 2026 08:23:42 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=donttrustverify.pt; s=protonmail; t=1788103421; x=1788362621; bh=lsxCdiVk2vQDHW3haf1IZ5ewxRQBzfr+0cfCABi6XRs=; h=Date:To:From:Cc:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=x/FWjarqUgGnjvdTTimUNd/dn+6jW2jFhDreFkF5G8kSLtBEm0UESAZyZFCZGVUQ+ HYgiixukoLkiGPYM5jo1pLtM2aKerfdFRBn0pXI7KQ1wnaWSDINizpF0BW690fvofC D5xZYotLhts1qrxmVpxDEYziLg05PZbS9nBmqfRuVWzaXbOzsXRAGE9xHqypfNWdQp a+iEIvksGFAqrHafVXNujJU601hvTJg+eoTherFhd0S/7ebqUXNYqklgtqq7RlcFsn cHg0MWX/DXQPLfEUeF1fCM9zq8wbHJAoe4boZb7dlPRrgz1cqidaRq1u8tBeuP+AeK 8+pXXT1Rvhoqg==
Date: Sun, 30 Aug 2026 15:23:36 +0000
To: "scitt@ietf.org" <scitt@ietf.org>
From: Tiago Pinto <tiago@donttrustverify.pt>
Message-ID: <465ITu9UnGDKZqwWdqZD94K1LFpJxYWWBF-ztLXONI909Mk8_ISvfB71dAY_PDolw0SE14uJyBQeRafcV4gBQqFjfYLf7xVrjuIewnurNJQ=@donttrustverify.pt>
Feedback-ID: 206570780:user:proton
X-Pm-Message-ID: 0d8659603f671ba903198b105b684fc249fc44b9
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Message-ID-Hash: O4QSUUTN7ZDP3SUX5M42EBZJ33VEGCXC
X-Message-ID-Hash: O4QSUUTN7ZDP3SUX5M42EBZJ33VEGCXC
X-MailFrom: tiago@donttrustverify.pt
X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header
CC: "e.dogru@conarium.dev" <e.dogru@conarium.dev>
X-Mailman-Version: 3.3.9rc6
Precedence: list
Subject: [SCITT] First-failure list: draft-dogru-cedulon-04
List-Id: "Supply Chain Integrity, Transparency, and Trust" <scitt.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/scitt/7DOQshWFo96zAGxizd8h23AELoI>
List-Archive: <https://mailarchive.ietf.org/arch/browse/scitt>
List-Help: <mailto:scitt-request@ietf.org?subject=help>
List-Owner: <mailto:scitt-owner@ietf.org>
List-Post: <mailto:scitt@ietf.org>
List-Subscribe: <mailto:scitt-join@ietf.org>
List-Unsubscribe: <mailto:scitt-leave@ietf.org>
Hi Emek, all, Taking up your offer from the thread on draft-pinto-agent-authz-contestability. I put -04 through the same kind of reading. I ran the Appendix A vectors before reading for failure points. Both Ed25519 signatures verify, the SPKI-derived kid is 06e3fd8fda29bb60, and deterministic re-encoding reproduces both protected headers and payloads byte for byte. Run against the exact IETF archive bytes, SHA-256 661755c600aede25451ce3a67df4a45d0d964c7b9196dc725dd310723eb8a49f, under Python 3.14.4, cbor2 6.1.4, and cryptography 50.0.1. My first failure is the transparency-receipt path. 1. I cannot implement steps 15 and 16 from the evidence the draft defines. Section 11.3 says that "A receipt binds a statement hash, not a statement" and that "the verifier computes the statement hash of each presented checkpoint itself." I do not think that is the verification mechanism defined by RFC 9942. RFC 9942 Section 5.2.1 requires the verifier first to apply the inclusion proof to the bytes of the candidate entry. The resulting Merkle Tree root becomes the detached COSE_Sign1 payload, and the signature is then verified over that root. For the SCITT use here, the candidate entry is the registered Signed Statement, not merely the checkpoint COSE object carried inside it. The audit evidence defined by -04 gives me the checkpoint, but I cannot find a requirement to present the exact outer Signed Statement bytes that were registered. That leaves two separate failures for an implementation. I do not have the candidate-entry bytes required to apply the RFC 9942 inclusion proof. Even if I had them, step 15 tells me to verify the receipt against the transparency key while the surrounding text describes this as authenticating a statement hash. RFC 9942 instead requires candidate entry, inclusion proof, Merkle root as the detached payload, and then signature verification. Section 18 already says that the current implementation treats a receipt as a signature over a statement rather than as proof of log membership, and that it has not been exercised against a real Transparency Service. My point here is narrower: the same simplification appears to have reached the protocol text and verification algorithm. Therefore I cannot implement the RFC 9942 verification path from the inputs and algorithm as currently stated. 2. I cannot determine the verification key or the resulting finding consistently in the unpinned branch. The Abstract says: "No signed object may be verified against a key it carries itself" MUST-T4-9 likewise requires the issuer public key out of band. The finding table nevertheless describes the unpinned case as one in which the receipt or checkpoint was checked using a key associated with the presented object. The COSE profile itself carries kid, but no public key. The unprotected header MUST be empty, and I cannot find a COSE_Key, x5chain, or other field from which to obtain the candidate public key. So in the no-pin case I cannot determine what key the signature is to be checked against. Step 4 then adds a second ambiguity. It first says to reject on Ed25519 failure or kid mismatch, and then says to apply the issuer root and report issuer-key-mismatch. For example, if kid differs from the configured issuer key, I cannot tell whether that is a rejection only or an issuer-key-mismatch finding. If kid matches but the signature is invalid under that key, I cannot tell whether the resulting condition is issuer-key-mismatch, receipt-chain-break, or something else. Those choices matter because a rejected receipt is removed from the attested set before reconciliation. Therefore I cannot derive one key-resolution path and one finding set from step 4. 3. I cannot construct one authenticated Rail Extract from the specification. Table 8 says: "Each settlement record MUST contain" ref, amount, currency, and timestampMs. The Authentication text then says: "The member names of that body are the rail's to define" Those are different rules. If the Table 8 names are normative, a rail cannot rename them. If the rail defines the names, Table 8 has not defined the signed record shape. I also cannot derive one complete signed JSON object containing the record set, windowStartMs, windowEndMs, the account and rail identifiers required by the scope rules, and the signature representation. Table 8 additionally uses tstr and uint, which are CBOR terminology, for a body that the next section says is JSON. Since the authenticated extract is the authoritative reconciliation input, therefore I cannot construct or verify the same Rail Extract from the text alone. 4. I cannot reconstruct one receipt order or one checkpoint-window result. Step 6 says: "Walk the attested receipts in issuer order." I cannot find a definition of issuer order. Presentation order, timestampMs order, and hash-chain order can differ. The draft itself notes that timestampMs is issuer-asserted, so temporal order cannot safely be assumed to be chain order. The same problem appears in chainHeadHash, which is the receipt hash of the "last receipt in that window". I cannot determine what makes a receipt last. There are two further boundary cases in step 12. Every chained receipt MUST fall in exactly one checkpoint window, but the document also contemplates audits with no checkpoints. With receipts and zero checkpoints, I cannot determine whether every receipt produces window-coverage or whether that check is skipped. The same question occurs for receipts in the currently open epoch after the last closed checkpoint. The dependency text also says "Nothing else in this list feeds another step." Taken literally, that is not true. Step 14 consumes checkpoints accepted by step 11, and steps 8 and 9 consume the index built by step 7. That matters because the same section permits evaluation in any order only where the resulting finding set is unchanged. Therefore I cannot derive one ordering rule, one definition of the in-window chain head, or one result for zero-checkpoint and open-epoch evidence. 5. Independent issuer and rail clocks can produce a completeness failure for an honest payment. Step 5 scopes receipts using the issuer's timestampMs. The extract is scoped using the rail's timestampMs. Consider a legitimate payment close to windowEndMs. If the rail records it just before the boundary and the issuer records its receipt just after, the settlement is inside the extract while its matching receipt is outside the reconciliation set. The reverse can happen with the clocks skewed the other way. Step 8 then reports settlement-without-receipt or receipt-without-settlement. This is not a same-evidence interoperability difference. Both verifiers can reach exactly the same false failure. Therefore I cannot see how a deployment with independent honest clocks avoids audit failures at window boundaries. I think one timestamp needs to control reconciliation membership, or the boundary treatment needs to be defined. 6. I can make an otherwise valid audit fail by appending a countersignature. Section 10.2 says: "Anyone holding an honest receipt can append a countersignature of their own" That is the right observation. But if the verifier has a payee key pinned, a bad countersignature or one under the wrong key causes the audit to fail. Take an honest issuer receipt that otherwise passes the audit. A party presenting the evidence appends an arbitrary countersignature. The issuer signature and receipt bytes have not changed, but the audit can now fail. That seems to give an appendable object that is not covered by the issuer signature the ability to manufacture a negative result. It is also close to the attack that the revised MUST-T8-9 avoids by refusing to let unauthenticated evidence create an accusation. Therefore I cannot see why a countersignature that cannot be attributed to the pinned payee should fail the underlying audit rather than be excluded with a finding or warning. 7. I cannot close the counterparty binding across manifest, receipt, and rail extract. The Trade Manifest does not identify the payee. The receipt does. The manifest comparison checks amount, currency, and expiry. The rail reconciliation checks ref, amount, and currency. The Rail Extract record defined in Table 8 does not contain a payee. Consider a valid manifest M published by A for 100 USD, a receipt naming M but paying B, and an extract row matching the receipt's ref, amount, and currency. The comparisons defined by the algorithm can all succeed. Perhaps a given rail guarantees that ref independently resolves to the beneficiary. If Cedulon relies on that property, I cannot find it stated as a required property of the rail profile. Therefore I cannot determine from the defined evidence that the counterparty named by the receipt is the counterparty to the offer and settlement being audited. 8. I cannot establish "what bytes were delivered" from the Dispute Evidence Bundle as defined. The Introduction says the audit layer gives a machine-checkable answer to: "what bytes were delivered?" The Trade Manifest commits to the expected bytes through acceptanceCriteriaHash. The Spend Receipt does not contain a delivery hash. The Dispute Evidence Bundle then consists of the manifest, receipt, and a delivery hash, but I cannot find a signature binding that delivery hash to this receipt or transaction. The optional payee countersignature signs the receipt, which also does not contain the delivery hash. So an auditor can verify a signed offer, a signed spend receipt, and a hash supplied alongside them. I cannot see what establishes that the third value was the hash of the bytes actually delivered in that transaction. Therefore I cannot derive the Introduction's delivery claim from the evidence bundle. Either the claim is narrower than that wording, or the observed delivery hash needs a signed transaction binding. One question rather than a failure. The Introduction also says Cedulon answers: "was this spend allowed by policy" I am unsure which claim is intended there. Is the auditor intended to independently verify the PDP allow that authorized the settlement, or to verify the Receipt Issuer's signed assertion that the spend passed its gate under the stated policyHash? As currently defined, I think it does the latter. The Decision Token contains requestHash, policyHash, expiryMs, nonce, and singleUseId, with requestHash covering the six request fields. The Spend Receipt does not contain requestHash, singleUseId, a Decision Token hash, or tool, and the verification algorithm does not consume a Decision Token. That can be a deliberate trust boundary. What made me stop on it is that Cedulon explicitly does not trust the Receipt Issuer alone for completeness, hence the authenticated rail extract, while I could not find the equivalent statement that authorization in the retrospective audit is an issuer assertion rather than independently verified PDP evidence. If the intended answer is the issuer assertion, I think stating that boundary would resolve the question. If the intended answer is independent verification of the PDP allow, I think a binding to the Decision Token is missing. Three mechanical points. Appendix A makes its vectors normative on their own terms, but the receipt vector carries policyHash = "aa" while Table 3 defines that claim as lowercase hexadecimal SHA-256. I reproduced the vector as signed. A validator enforcing the claim definition rejects it; a decoder treating it as an unrestricted tstr accepts it. T8 contains both MUST-T8-9 and MAY-T8-9, although the document defines k as the sequence number within that threat. Those are two different requirements sharing the same T8 sequence number. The RFC 8785 lone-surrogate paragraph says an implementation MAY emit the escaped form instead of failing. RFC 8785 Section 3.2.2.2 says occurrences of lone surrogates MUST cause a compliant JCS implementation to terminate with an error. Those are my first failures on -04. I stopped here rather than turn this into a prose review. Best, Tiago Pinto Independent author and researcher, verifiable trust and AI governance https://donttrustverify.pt
- [SCITT] First-failure list: draft-dogru-cedulon-04 Tiago Pinto
- [SCITT] Re: First-failure list: draft-dogru-cedul… e.dogru
- [SCITT] Re: First-failure list: draft-dogru-cedul… Tiago Pinto
- [SCITT] Re: First-failure list: draft-dogru-cedul… e.dogru
- [SCITT] Re: First-failure list: draft-dogru-cedul… Tiago Pinto
- [SCITT] Re: First-failure list: draft-dogru-cedul… e.dogru