[SCITT] Re: New draft: The Coverage Attestation Profile (draft-hillier-coverage-attestation-00), and a request to break it

Konrad Gruszka <kontakt@b7n0de.com> Tue, 01 September 2026 17:47 UTC

Return-Path: <kontakt@b7n0de.com>
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 76EB813346FDB for <scitt@mail2.ietf.org>; Tue, 1 Sep 2026 10:47:09 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ietf.org; s=ietf1; t=1788284829; bh=mjfqdjb0y74Zh7jbezTZdJhM6n/811QyBhMilmVhEYo=; h=Date:To:From:Subject; b=h8ZwZnwiV/CNB8HHqY4qJD/G9EDKn18OSpWq4pcMWI9Oe21IPNE1cqOuYWZlzNcfy E1Gd1qq+mSCG8w6rEKRou2UJj6FSyeFB1Yld+w1KiOE/0jQ6GFTVoQ36FQEaRFdDUN r/TdVMpA+gx4laV95v4QzCXM5Xg+9bzDzDzr5HZw=
X-Virus-Scanned: amavisd-new at ietf.org
X-Spam-Flag: NO
X-Spam-Score: -1.204
X-Spam-Level:
X-Spam-Status: No, score=-1.204 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DATE_IN_PAST_03_06=1.592, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, 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=no autolearn_force=no
Authentication-Results: mail2.ietf.org (amavisd-new); dkim=pass (2048-bit key) header.d=b7n0de.com
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 sVk-lkjaw4HJ for <scitt@mail2.ietf.org>; Tue, 1 Sep 2026 10:47:08 -0700 (PDT)
Received: from mail-24422.protonmail.ch (mail-24422.protonmail.ch [109.224.244.22]) (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 1A76013346FD6 for <scitt@ietf.org>; Tue, 1 Sep 2026 10:47:08 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b7n0de.com; s=protonmail; t=1788284826; x=1788544026; bh=mjfqdjb0y74Zh7jbezTZdJhM6n/811QyBhMilmVhEYo=; h=Date:To:From:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=xFRjaax8nnIZFGH9akEW0KGreOKW7ZgArWCBAFYlyz36GrG8hN3ZmE2wUSRDlhLu0 ozMuSDjMUUAvqOnTeXcx9sJ4TWVf2xBgGPgcj5haZgSm6t6LQWZ2TDXKiZoY0+yiwR nf9X8nM78SkO2XWZDfGl0H90NSmt+IkS7ewtRrNkiEBu0cPKLs5o/9ppvX/d4LoFeo 7JDCcfoh7HbTCJevFLDJdBtAuTZzZAY2AkLAoBJJffSFKveK3v0DpvFha586VgubLr fjitEKMPrWUkl5KoctGfaLMlBSSCUCjHK5El+TuQr/V17MC2IWWiQ31wS0N4+nIuu5 3D/hapJg2mDkw==
Date: Tue, 01 Sep 2026 14:28:36 +0000
To: "scitt@ietf.org" <scitt@ietf.org>
From: Konrad Gruszka <kontakt@b7n0de.com>
Message-ID: <BeHy9sIOsFRvvLgXq9bIrFgGFshx8dZLjOUqyQh96RpbzJg4Nxbm7KVOUU2k9Sp37vCF7Aly8e4t-GXzucakA-MMreu37LjKWbnwLeR9Jmc=@b7n0de.com>
Feedback-ID: 210251687:user:proton
X-Pm-Message-ID: 7c171f478f0969c2064c8a3878a48559e6e7adf4
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="b1=_mffq2Q6p9LctxplyxK0kHqmxVn8u3FsT3PDrQGiVhI"
Message-ID-Hash: OP3APMZBAX4JKVSUVK6ZMZ7R74MR5WAW
X-Message-ID-Hash: OP3APMZBAX4JKVSUVK6ZMZ7R74MR5WAW
X-MailFrom: kontakt@b7n0de.com
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
X-Mailman-Version: 3.3.9rc6
Precedence: list
Subject: [SCITT] Re: New draft: The Coverage Attestation Profile (draft-hillier-coverage-attestation-00), and a request to break it
List-Id: "Supply Chain Integrity, Transparency, and Trust" <scitt.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/scitt/ROY0pfUEbWg3A5BteF5YXz7Q-UE>
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>

Joel, all,

I read the thread before writing, and I have dropped what Emek, Walter, Tiago and Anton
already have. What is left is one implementation report and one ambiguity I could not find
anywhere above.

First, what this is not. Emek ran two text-derived readers on 21 August and they disagreed
on 15 of 15, with one root: the draft did not name the members. Mine agree. That is not a
better result, it is a later one, and the difference is your repairs and the pinned bundle
rather than anything I did. If it is worth anything it is as a measurement of whether the
repair took, from someone who was not in the thread when it was made.

What I ran. Two verifiers written from the prose of Sections 4, 4.1, 4.2, 4.3, 5 and 6,
with the field names from CAP-1.schema.json. One is Python standard library. The other is
Rust with no dependencies and a hand-written JSON reader, so the two share no parsing path.
I did not read verify.mjs, verify.py or verify.html; copying them would have measured one
reading twice.

Against cap-1 at 0980d32, with core.autocrlf and core.eol unset, no .gitattributes, a clean
git status and zero checked-out files carrying CRLF:

The numbers. Both readers pass 15 of 15 against the conformance class, and Python vs Rust
agree 15 of 15. Against runs/conformance_run.json the exact set of rules fired matches,
including NC-05 firing both R5 and R1. cap-1.zip reproduces at 645dcc47a0082e48... and
verify.html at 62ede737312cefc4..., and the mail-safe repack is 40 of 40 byte-identical
after restoring extensions.

Then I probed eight places where the prose is silent. Seven times all three readers agreed.
The eighth is the reason for this message.

CAP-1 does not say what a verifier does with duplicate names in a JSON object. RFC 8259
Section 4 says names SHOULD be unique and calls the behaviour on violation unpredictable.

Take PV-03 and give integrity.complete twice, first true then false. PV-03 carries a failed
unit, so R7 forbids complete: true there.

A last-wins reader sees false and CONFORMS, which is also what verify.py does, measured.
A first-wins reader sees true and is REFUSED under R7. A strict reader rejects the
document as malformed JSON.

The other direction flips which reader accepts: PV-01 with eligible given twice, first 6
then 13, is refused under R1 by last-wins and accepted by first-wins.

Same bytes, three conforming readers, three answers. A producer can ship one document that
one relying party reads as clean and another refuses.

What makes this worth a clause rather than a footnote about JSON hygiene. The
duplication is the symptom. The property at risk is determinism. CAP-1 exists so that a
relying party can rely on a count, and here the count is the payload. If which count a
reader sees depends on which parser it used, the attestation is unreliable in exactly the
property the profile was written to establish. That argument is not mine; it came out of an
adversarial reading of my own finding, which is also where four attempted refutations of it
died.

Why I think this belongs with your eight classes rather than beside them. Your framing on
21 August was that two byte strings carry the same information and a digest over them
differs, so the information is invariant and the representation is not. This is the mirror.
The representation is invariant and the information is not: one byte string, two conforming
parsers, two different documents.

That has a consequence for the canonicalisation thread. JCS operates on parsed JSON. By the
time it runs, the parser has already chosen a winner, so canonicalisation cannot reach this
one. It sits a layer below everything in that discussion. Emek's open item, that nothing
pins whether a count is 25 or "25" except a schema outside the preimage, is the same shape
one step earlier: there it is which type, here it is which value.

Not the same as Anton's item of 25 August. His duplicate unit identifiers sit inside
unexamined and let R1 close by addition; that is the accounting layer, and one clause in R1
or R2 settles it as he says. This is the parse layer, and a clause in R1 would not reach it.

Harmless readings I checked and ruled out. R0 requires stratum identifiers to be unique and
does catch a duplicated stratum id, measured, in both my readers and in yours; it does not
reach object keys. JSON Schema has no vocabulary for duplicate names, so
additionalProperties: false does not help. It is not in run.mjs's declared gaps, which name
R0 isolation, author independence, and timing, ordering and concurrency, and not in the
self-attestation.

One correction against myself, because it nearly became a false report. My first Rust reader
read digits greedily and accepted "examined": 04, which RFC 8259 Section 6 forbids. My own
probe caught it, and it looked like a divergence in your document before it looked like my
bug. After the fix all three agree and the fifteen still hold.

What I would suggest, in your idiom: a document containing duplicate names within any object
MUST be refused. That is what my strict reader already does, and it costs nothing for
documents that were already well behaved.

The probe package is small, runs from a clean copy with Python 3 alone, and generates the
probes from your tree rather than shipping your vectors. It carries positive controls, two
unaltered vectors that must show CONFORMS and one simple R1 break that must show REFUSED,
so a run that refuses everything is visible as such rather than looking like a perfect score.

It is here, pinned to a commit rather than a branch, so the bytes you fetch are the bytes I
ran:

https://github.com/b7n0de/proofbundle/tree/96dacc4c12015e2859ae31955420707459663a1d/tools/cap1_unabhaengige_umsetzung

I have not written anything against -01, since -00 is the only version posted.

Prepared with AI agent involvement, reviewed and submitted under human oversight.

Konrad Gruszka
b7n0de · Verified AI Workhttps://b7n0de.com