Skip to content

windeploy: fix the detached Windows signing path - #490

Open
reddink wants to merge 3 commits into
developfrom
build/win-codesign-cert
Open

windeploy: fix the detached Windows signing path#490
reddink wants to merge 3 commits into
developfrom
build/win-codesign-cert

Conversation

@reddink

@reddink reddink commented Aug 21, 2026

Copy link
Copy Markdown
Member

Two fixes to contrib/windeploy/, both inherited from upstream and never adjusted for Reddcoin.

1. The signing certificate belongs to Bitcoin Core and expired in 2022

contrib/windeploy/win-codesign.cert still holds Bitcoin Core Code Signing LLC's certificate:

subject   = C = US, ST = Delaware, L = Lewes,
            O = Bitcoin Core Code Signing LLC, CN = Bitcoin Core Code Signing LLC
issuer    = C = US, O = DigiCert Inc, CN = DigiCert SHA2 Assured ID Code Signing CA
notBefore = May 21 00:00:00 2021 GMT
notAfter  = May 26 23:59:59 2022 GMT

Why this matters

The detached Windows signing path cannot work. contrib/windeploy/detached-sig-create.sh hardcodes the file as -certs:

"${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -h sha256 \
                       -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"

That pairs Bitcoin Core's certificate with our signing key, which cannot produce a usable signature.

The rest of the machinery is sound and mirrors macOS. The script runs extract-signature -pem into win/<name>.exe.pem and tars it as signature-win.tar.gz for the detached-sigs repo, and contrib/guix/libexec/codesign.sh reattaches it:

osslsigncode attach-signature -in "$infile" \
    -out "${OUTDIR}/${infile_base/-unsigned}" \
    -sigin codesignatures/win/"$infile_base".pem

So guix-codesign is capable of signing Windows and macOS in one pass, but the certificate makes it unusable. Windows is currently signed by invoking osslsigncode sign by hand against the hardware token, then placing the output and writing SHA256SUMS.part manually.

Every release ships the stale certificate. reddcoin-4.22.9.4-win-unsigned.tar.gz contains win-codesign.cert byte for byte identical to the file in the repo. Nothing downstream consumes it, so it is inert, but it means our release artifacts publish an unrelated organisation's expired certificate.

The change

Replaces the file with the Redd Ink Technology Pty Ltd code signing certificate and its Sectigo chain, keeping the leaf/intermediate/root layout of the file it replaces (which was also three certificates):

Redd Ink Technology Pty Ltd            expires 23 Oct 2026
Sectigo Public Code Signing CA R36
Sectigo Public Code Signing Root R46

Provenance

The leaf is the part that matters, so it was not downloaded from anywhere:

  • exported directly from the signing token with p11tool --export 'pkcs11:...;type=cert'
  • sha256 fingerprint 30:E8:7F:73:54:09:FC:F8:96:FB:C9:CB:E3:DA:29:78:E2:7D:55:95:A8:74:90:C2:9B:2A:09:45:AD:4C:10:98
  • identical to the leaf embedded in reddcoin-4.22.9.4-win64-setup-signed.exe, the installer signed with that token, so it is provably the certificate we sign with

Intermediate and root were fetched from the AIA URLs the certificates themselves advertise on crt.sectigo.com, rather than from a search result. The chain verifies:

$ openssl verify -CAfile R46.pem -untrusted R36.pem token-cert.pem
token-cert.pem: OK

One wrinkle worth recording: Sectigo's .p7c for R46 carries three variants, the self-signed root plus two cross-signed ones (USERTrust RSA CA, and Comodo AAA Certificate Services). Concatenating it wholesale would have produced a five certificate file. Only the self-signed root was taken, matching the structure of the file being replaced.

2. Timestamping used a Comodo-era alias

detached-sig-create.sh hardcoded TIMESERVER=http://timestamp.comodoca.com, while releases signed by hand have used http://timestamp.sectigo.com. The two routes disagreed on which endpoint to trust.

This changes no behaviour today. Both hosts answer, and an RFC3161 round-trip against each is granted by the same authority:

$ openssl ts -query -data f -no_nonce -sha256 -cert -out req.tsq
$ curl -H "Content-Type: application/timestamp-query" --data-binary @req.tsq <host>

timestamp.sectigo.com    Status: Granted.  TSA: Sectigo Public Time Stamping Signer R37
timestamp.comodoca.com   Status: Granted.  TSA: Sectigo Public Time Stamping Signer R37

That signer is also the TSA in the 4.22.9.4 installer's signature. The change pins the name the service is actually operated under rather than relying on a legacy alias outliving the company that owned it.

It is also now overridable from the environment, the same way OSSLSIGNCODE already was, so switching endpoints does not mean editing the script:

TIMESERVER=http://timestamp.example.test ./detached-sig-create.sh -key ...

Verified with a stub signer standing in for osslsigncode, so no token was involved: default run passes -t http://timestamp.sectigo.com, overridden run passes -t http://timestamp.example.test.

CERTFILE and the sha256 digest are deliberately left fixed. Both are properties of what is being signed rather than of the environment signing it.

Scope

develop only. v4.22.9-regtest is deliberately untouched: it is tagged v4.22.9.4 and that release is already built, so changing it would break correspondence between the tag and the shipped tarball.

Both changes are confined to contrib/windeploy/. Neither alters how releases are signed today, since the direct route does not read either file.

Whether to move Windows signing onto the detached flow is a separate decision, recorded in the issue. These two fixes are what make it possible: osslsigncode supports -certs <certfile> -key <pkcs11 URI> (documented in its own sign --help), so detached-sig-create.sh can be driven through its "$@" pass-through with the hardware token.

Renewal

The replacement leaf expires 23 Oct 2026. This file must be regenerated from the token when the certificate is renewed, or the detached path breaks again in exactly the same way.

YouTrack: https://reddink.youtrack.cloud/issue/RED-97

win-codesign.cert still held Bitcoin Core Code Signing LLC's certificate,
inherited from upstream and expired 26 May 2022. contrib/windeploy/detached-sig-create.sh
passes it to osslsigncode as -certs, so the detached Windows signing path
could never produce a usable signature: the certificate does not match the
key Reddcoin signs with. The same file is packaged into the release as
win-unsigned.tar.gz, so every release has shipped an unrelated expired
certificate.

Replace it with the Redd Ink Technology Pty Ltd code signing certificate
exported from the signing token, plus its Sectigo chain, mirroring the
leaf/intermediate/root layout of the file it replaces:

  Redd Ink Technology Pty Ltd  (expires 23 Oct 2026)
  Sectigo Public Code Signing CA R36
  Sectigo Public Code Signing Root R46

The leaf is sha256 30:E8:7F:73:54:09:FC:F8:96:FB:C9:CB:E3:DA:29:78:E2:7D:
55:95:A8:74:90:C2:9B:2A:09:45:AD:4C:10:98, the same certificate embedded in
the 4.22.9.4 installer signed with that token. The chain verifies with
openssl verify against R46 as anchor.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

detached-sig-create.sh timestamped against http://timestamp.comodoca.com,
a Comodo-era hostname inherited from upstream. Releases signed by hand have
used http://timestamp.sectigo.com instead, so the two routes disagreed on
which endpoint to trust.

Both hosts currently answer, and an RFC3161 round-trip against each is
granted by the same authority, Sectigo Public Time Stamping Signer R37,
which is also the TSA in the 4.22.9.4 installer's signature. So this changes
no behaviour today. It pins the name the service is actually operated under
instead of relying on a legacy alias outliving the company that owned it.
@reddink reddink changed the title windeploy: replace the inherited Bitcoin Core signing certificate windeploy: fix the detached Windows signing path Aug 21, 2026
The timestamp endpoint was a plain assignment, so switching it meant editing
the script, which is awkward when the authority changes hands or is briefly
unreachable and a release is waiting.

Give it the same treatment OSSLSIGNCODE already has and default it to the
sectigo endpoint. CERTFILE and the sha256 digest stay fixed: both are
properties of what is being signed rather than of the environment signing it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant