[SCITT] Signed Statement identity when the ECDSA signature is not byte-unique
Anton Sokolov <anton.sokolov@tyche.institute> Tue, 18 August 2026 12:15 UTC
Return-Path: <anton.sokolov@tyche.institute>
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 5DAF512B9AB8B for <scitt@mail2.ietf.org>; Tue, 18 Aug 2026 05:15:55 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ietf.org; s=ietf1; t=1787055355; bh=p+yrHeascekoT1o1H3Lyt1HzaQIv0jM7AmpZuX9Fim8=; h=From:Date:Subject:To; b=R8h9U4ebXFZrZ/Q85XFrGUG9cQed5fJxgOd0uaSkml7QYdHxawzpsZ3XJo2Dmm+XQ uh1TVvddUKLhycmZtjt1yjxbDmzNSkMrwJ7dMul26EMHLm05cEcnfzn3s9rbxTcsDy JASXrnaxcvCqzSW/b8qWTBGK+hNopb0NbKWTysBI=
X-Virus-Scanned: amavisd-new at ietf.org
X-Spam-Flag: NO
X-Spam-Score: -2.099
X-Spam-Level:
X-Spam-Status: No, score=-2.099 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, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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=tyche.institute
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 A7wKtMPgiOWE for <scitt@mail2.ietf.org>; Tue, 18 Aug 2026 05:15:54 -0700 (PDT)
Received: from mail-yx1-xb12e.google.com (mail-yx1-xb12e.google.com [IPv6:2607:f8b0:4864:20::b12e]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mail2.ietf.org (Postfix) with ESMTPS id B045712B9AB84 for <scitt@ietf.org>; Tue, 18 Aug 2026 05:15:54 -0700 (PDT)
Received: by mail-yx1-xb12e.google.com with SMTP id 956f58d0204a3-66c71239c48so6430491d50.2 for <scitt@ietf.org>; Tue, 18 Aug 2026 05:15:54 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1787055348; cv=none; d=google.com; s=arc-20260327; b=YFLRuVTXHHaN3NdDx3pqHt+zsl8Rhkn3qaZtya6IOhr4JYK7ESbl7wqbpD3JqsMd61 P2udz/vflIYQIBPQjytXpx3ldR7IQyJiDymAtLX5cuBy33f2BGiWT1AlBZf/xfLjlpEX EdVSX6kDnBmBj5PpDLsWFSrJi/fogFs6lZQIInBDwQ4kTkp6/b73YjRGyd8CGY21wevI kjkhfsyaDbzqxWgskc0d9qB7uXW7E1ZiedvghxOg9gkaVPvAM2sl9c60tidODhKhHMUG cIqNJHupKHCaSEsx9Sh94vrQBZvx4AKLi/KTqIAfuXbwbLEEUEaC12aXly7zlQ3wPwm6 gxLQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=CSRyzchikMG7eCKxGFH0gwfwC9OOkAJQBDU4EBmuP7w=; fh=Anxmu+iCZVTaF0nwB+Di1xcbGc8IAUY7lT1BcRHJn1c=; b=a4UKo0RVI5k86BFrp/J19Pi/6oXpPulgVTiP+rmzAYsdxJoNnrVYhgVb+zYHB2qZnR grEG+lsjNdnQ/85UICk5UImj9w9hr5K6HvG3HTpxwYdl4C1i2SBdSMXUFclD2lVeJis2 jGpQiMm0Jok+BfXDgtyeyCJMXrygeKm6L6fGL2lCdpqwIn2R4+Wc7RWXPNjQdID0PLz7 ubEMuKNShlRs+NL5sBE+FrXf/WuCeQNIlTko6xPbSbkgWhyQkJVx0NjRp+0atDJCIrVX MDr/QPfBe1OM7P2HjgMb6tgPhPhH6UV/Au/o80+jaLyjZ7BqdwPM6pIOQOluoueVJcfC Cr8w==; darn=ietf.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tyche.institute; s=google; t=1787055348; x=1787660148; darn=ietf.org; h=content-type:to:subject:message-id:date:from:mime-version:from:to :cc:subject:date:message-id:reply-to:content-type; bh=CSRyzchikMG7eCKxGFH0gwfwC9OOkAJQBDU4EBmuP7w=; b=NodY68teB39oRzpixZzOjhibfCFDwSQCtCSXmEfP020saIxOFCsz904bEGC/08s3YH huxbuxEq/EXpUqyNZimn7GcaahoXHv/50eC+iIxABsCwGmCFQK5tNKSYpqa0dA5qFbLW KZRE7aJ2nLP7Cqv8GMF1F3bvY/NyYBPeswqvRw2uLeip3qxywqA/2FI+JmpSwZkDOypt xef6ChbiWJTDQDrESLTI5K+XtiqRDhtsvb472x/U/VSegqVhfoSiHBOy+8iCcny7wJ9k Kw7M56MykkFP9aO5GYfrOK5wjply85HVX1rxg/sgRMeWmH/uI9nZwe5FBy+gO3EyPejU ZjHQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787055348; x=1787660148; h=content-type:to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=CSRyzchikMG7eCKxGFH0gwfwC9OOkAJQBDU4EBmuP7w=; b=n1pYiD0jAe7654EFBVNZaF5N1xIZdvLzVBq5MUdLoGO4hkZfPooD4Vm1FvIeLnkMg7 eRjtXW4OGKRn6grCdS2IfCmoemV9YD3W8Rf0Cs5k7lhE2nx31fnhCm5TfKgaQf5LnhkX ZglLNiAWTHPmiPF6/Q3cofCXeRPjoQY0zH5OWbiWaO6wLsqoEQ0ZOS1K2fRbE3zjjAc/ bfeFppYNd+uAjZXph2zsRtBMHjYG0uVQxoXrFBuLQ3oZtifJawmOwRG2hE7thvPQ1Wf6 7aRa/msiCPfleRHtfE3vaNjq6r8Gq+xVi1Xk7aUnR/8vElAKUHK8Y3UWSUJ6jbScUmpn sIuA==
X-Gm-Message-State: AOJu0YxlumIYfQoJmlzmo4wY3BmRJ9eePYhde/VmHl7owt1JxTDQqIq0 4eReuEmW/ytAbzMCwHXkQvnhp0eqqAQt+r+szU0HmhvMdQPlfM/krc9RVt0oijNj1798cYpvyt7 rgDQmnBcmE2UTc6WDOSFToo8wKWUpkfXesRQ9H+aTYAY3GbU/vyHTiTd7
X-Gm-Gg: AR+sD10IDOJ87Fs/soHUTU3IhxUgMpRQtrlivtsAneUHk9j65GlOMMCbT2Sz2E34E1C foKVDpxpkH9XY0PTKiIt1lBwhph2znBxJxlqSVMV+nRPfB/bYEvB4+4JnuzKkEiPGerP160azLS y8jnnuA1DQNHuzpemZ0UjAuiedNNNwtAgVyVSVHP0eCnKpCaVuZI55Q9oURAw8gtopBoKMkbBwc iRLi3gV6fhhU8x1KWhuF1UtIRLZtRzxXlqzW/LFGyXE1lp7qXSMw+MuaV42UMnJvvqTL3i2ye1n RqzigRDiEcrJ5H3RnvnEK93FRCWhYz24BXYtMApS8HTcFnjNtpjhpjMp7cs7I4l2txlBZyNNERZ dSRuYKnq93Akf+EJz/VNz4CCQMpQH31dVaTs0Y79Bhv29zyxOAR75KuhqLi3aw/tOTSv2p/pqHS f/xKHmDHOASwX6dlxepeVt
X-Received: by 2002:a05:690e:12c9:b0:66c:51c5:61df with SMTP id 956f58d0204a3-66cb9e990f0mr2919628d50.44.1787055347587; Tue, 18 Aug 2026 05:15:47 -0700 (PDT)
Received: from 101988054943 named unknown by gmailapi.google.com with HTTPREST; Tue, 18 Aug 2026 07:15:46 -0500
Received: from 101988054943 named unknown by gmailapi.google.com with HTTPREST; Tue, 18 Aug 2026 05:05:13 -0700
MIME-Version: 1.0
From: Anton Sokolov <anton.sokolov@tyche.institute>
Date: Tue, 18 Aug 2026 07:15:46 -0500
X-Gm-Features: AcwNN1VJpzG4wAWmiQ3VWfnGcfGErhEp9Z58Dh7w7vqmNwp2X_rtXZdT6jrs85U
Message-ID: <CAMkGB8MLjYS8vohFpzcuA=hDiQKz3MMnndaq-H46jLM7aVbGvQ@mail.gmail.com>
To: scitt@ietf.org
Content-Type: multipart/alternative; boundary="0000000000002fedbc0659513f0f"
Message-ID-Hash: PGNGWPVSQB3B6I7TASQ4JKMCHDR537XA
X-Message-ID-Hash: PGNGWPVSQB3B6I7TASQ4JKMCHDR537XA
X-MailFrom: anton.sokolov@tyche.institute
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] Signed Statement identity when the ECDSA signature is not byte-unique
List-Id: "Supply Chain Integrity, Transparency, and Trust" <scitt.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/scitt/fzyFaUKmPlrDxibLm6Ejq7PEABg>
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 all,
Reproduction first. Any P-256 key, OpenSSL only, about ten seconds:
openssl ecparam -genkey -name prime256v1 -noout -out k.pem
openssl ec -in k.pem -pubout -out pub.pem
printf 'one act' > msg
openssl dgst -sha256 -sign k.pem -out a.der msg
N=FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
R=$(openssl asn1parse -inform DER -in a.der | sed -n '2s/.*INTEGER *://p')
S=$(openssl asn1parse -inform DER -in a.der | sed -n '3s/.*INTEGER *://p')
S2=$(echo "obase=16; ibase=16; $N - $S" | bc | tr -d '\\\n')
i(){ v=$(echo "$1" | sed 's/^\(00\)*//'); [ $((${#v} % 2)) = 1 ] && v="0$v"
case ${v:0:1} in [89A-Fa-f]) v="00$v";; esac
printf '02%02x%s' $((${#v}/2)) "$v"; }
B=$(i "$R")$(i "$S2"); printf '30%02x%s' $((${#B}/2)) "$B" | xxd -r -p >
b.der
openssl dgst -sha256 -verify pub.pem -signature a.der msg
openssl dgst -sha256 -verify pub.pem -signature b.der msg
sha256sum a.der b.der
Both print "Verified OK". The two files have different SHA-256. I ran this
over
200 random keys: 200/200.
No specification is violated. SEC1 v2.0 4.1.3 permits the substitution
verbatim
-- "The signer may replace (r, s) with (r, -s mod n), because this is an
equivalent signature" -- and FIPS 186-5 6.4.2 and SEC1 4.1.4 range-check r
and s
only. RFC 9053 2.1 enumerates the ES256 key checks and none constrain s. So
this
is a profile question for SCITT, not a defect in ECDSA, in COSE, or in
anyone's
library. It started with a shipping secure element emitting a high-s
signature;
that device is conformant, and I mention it only to show high-s is not a lab
curiosity.
The mechanism is old and I am not claiming it. Bitcoin addressed it in
BIP-62 and
BIP-146, and RFC 8032 8.4 says "Ed25519 and Ed448 signatures are not
malleable due
to the verification check that decoded S is smaller than l". Closer to home,
action-state-group/scitt-cose already documents it in its hardening notes
(finding
L2): "a COSE_Sign1's 64-byte signature is not byte-unique. Anyone keying
idempotency/dedup on the signature bytes ... must account for this."
What I do not think is on the record is the consequence for entry identity,
plus
one correction to that same note, whose closing sentence reads: "The leaf
digest --
what the transparency log commits to -- is over the full statement bytes
and is
unaffected in practice for the canonical signer." Being over the full
statement
bytes is precisely what makes it affected: those bytes include the
signature.
Keying an entry on SHA-256(COSE_Sign1) yields two entries for one signing
act;
keying on SHA-256(Sig_structure) yields one. I measured that with an
instrumented
log.
And not only with software keys. A commodity secure element -- an ECDSA
P-256 key
generated on-die in a PIV slot, non-extractable, with a touch policy the
device
attests, so every signature required a physical touch -- produced a
COSE_Sign1
whose signature is high-S. Its malleated twin verifies too:
sha256(original) =
87044ba351d8ce4aff9b3bd6c4b1a254a67b88cb43360acf2f42e66ae42b6d89
sha256(twin) =
d374e5d49a5d68364cc2b1d0611e537c9477c29efcf3839e592c642e2cb81f09
One act, one hardware-held key, one human touch, two valid receipts with
different
identifiers. Both files are 395 bytes and I will send them to anyone who
wants
them. That device is conformant and I am not reporting a vulnerability in
it --
which is the point: nothing anywhere is misbehaving.
This is not the duplicate-registration case the WG has already settled
(Lasker,
Jul 2024; also PR #351). The difference is who can produce the second
entry: here
it is produced by someone who does not hold the signing key, from the
first, in
transit -- and a relying party cannot tell that entry apart from an
issuer-intended re-registration. Nothing is forged and no authority is
bypassed;
the signer's authority is identical in both copies. It is about the
arithmetic of
counting.
The first reply to this is "mandate low-S", so: measured, not argued. Ten
signatures over one Sig_structure with random k, each normalised to low-S,
give
ten distinct SHA-256(COSE_Sign1) and one distinct SHA-256(Sig_structure).
Low-S
removes one byte-string per act out of many. RFC 6979 does not close it
either --
RFC 9053 2.1 already SHOULDs deterministic ECDSA, but determinism
constrains an
honest signer's choice of k; it does not shrink the set of byte-strings that
verify, and the twin above verifies against a deterministic signature
exactly as
well. A Transparency Service can observe neither property. For what it is
worth,
the secure element above does not do deterministic ECDSA: five signatures
over one
byte-identical structure gave five distinct r values.
The proposal, one sentence: derive the entry identifier from the
Sig_structure
rather than from the enveloped bytes -- noting honestly that this is total
where
canonicalising the signature is not, because the Sig_structure excludes the
signature by construction whereas a low-S rule only removes the cheapest of
infinitely many valid encodings.
The part that needs care: a Sig_structure-keyed identifier deliberately
collapses
two registrations of the same act, which is a distinction the WG wanted to
keep. I
would argue that is the right place for the seam -- identity of the act
from the
signed bytes, identity of the registration event from an explicit
registration
component, which is what at least one implementer already does (robinbryce
in
issue #321: H(DOMAIN-SEPARATOR || EXTRABYTES || IDTIMESTAMP ||
SERIALIZEDBYTES)) --
rather than inheriting it from whatever entropy the signature happened to
carry.
draft-ietf-scitt-architecture PR #145 documented the reverse direction of
this
trade in an appendix that was dropped in -11.
Where it touches the documents, for what that is worth given where they
are: RFC
9943 6.3 requires the unprotected header to be set to an empty map before a
Signed
Statement enters a Statement Sequence -- it pins one malleable field, and
the
signature is the other one. And draft-ietf-scitt-scrapi-11 2.3.1 requires a
service
to "return the same Location URL for the same registered Signed Statement"
without
defining "the same" byte-wise; EntryID appears four times (twice more as
"entry ID"
in example errors) and is defined neither in 1.2's imported terms nor in
RFC 9943.
If "the same" is meant byte-identical, the consequence is just that a third
party
can mint extra entries for one act -- worth resolving either way.
I am not asking for SCRAPI to be pulled out of the RFC Editor queue. I am
flagging
this for a future -bis and for implementers reading it now, and I will
carry the
measurement in draft-mih-sokolov-scitt-payload-binding. Happy to open a
tracker
issue instead if the chairs prefer, and happy to post the full measurement
(eleven
verification paths over four verifier cores, with negative controls) if it
is
useful.
Anton Sokolov
Tyche Institute, Tallinn
- [SCITT] Signed Statement identity when the ECDSA … Anton Sokolov
- [SCITT] Re: Signed Statement identity when the EC… Henri Sirkkavaara
- [SCITT] Re: Signed Statement identity when the EC… Joel Hillier
- [SCITT] Re: Signed Statement identity when the EC… Henri Sirkkavaara
- [SCITT] Re: Signed Statement identity when the EC… Henri Sirkkavaara
- [SCITT] Re: Signed Statement identity when the EC… Joel Hillier
- [SCITT] Re: Signed Statement identity when the EC… e.dogru
- [SCITT] Re: Signed Statement identity when the EC… Anton Sokolov